LCOV - code coverage report
Current view: top level - chart2/source/view/charttypes - PieChart.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 277 462 60.0 %
Date: 2014-11-03 Functions: 30 36 83.3 %
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 "PieChart.hxx"
      21             : #include "PlottingPositionHelper.hxx"
      22             : #include "AbstractShapeFactory.hxx"
      23             : #include "PolarLabelPositionHelper.hxx"
      24             : #include "macros.hxx"
      25             : #include "CommonConverters.hxx"
      26             : #include "ViewDefines.hxx"
      27             : #include "ObjectIdentifier.hxx"
      28             : 
      29             : #include <com/sun/star/chart/DataLabelPlacement.hpp>
      30             : #include <com/sun/star/chart2/XColorScheme.hpp>
      31             : 
      32             : #include <com/sun/star/container/XChild.hpp>
      33             : #include <rtl/math.hxx>
      34             : 
      35             : #include <boost/scoped_ptr.hpp>
      36             : 
      37             : using namespace ::com::sun::star;
      38             : using namespace ::com::sun::star::chart2;
      39             : 
      40             : namespace chart {
      41             : 
      42             : struct PieChart::ShapeParam
      43             : {
      44             :     double mfUnitCircleStartAngleDegree;
      45             :     double mfUnitCircleWidthAngleDegree;
      46             :     double mfUnitCircleOuterRadius;
      47             :     double mfUnitCircleInnerRadius;
      48             :     double mfExplodePercentage;
      49             :     double mfLogicYSum; // sum of all Y values in a single series.
      50             :     double mfLogicZ;
      51             :     double mfDepth;
      52             : 
      53          40 :     ShapeParam() :
      54             :         mfUnitCircleStartAngleDegree(0.0),
      55             :         mfUnitCircleWidthAngleDegree(0.0),
      56             :         mfUnitCircleOuterRadius(0.0),
      57             :         mfUnitCircleInnerRadius(0.0),
      58             :         mfExplodePercentage(0.0),
      59             :         mfLogicYSum(0.0),
      60             :         mfLogicZ(0.0),
      61          40 :         mfDepth(0.0) {}
      62             : };
      63             : 
      64             : class PiePositionHelper : public PolarPlottingPositionHelper
      65             : {
      66             : public:
      67             :     PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset );
      68             :     virtual ~PiePositionHelper();
      69             : 
      70             :     bool    getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const;
      71             : 
      72             : public:
      73             :     //Distance between different category rings, seen relative to width of a ring:
      74             :     double  m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
      75             : };
      76             : 
      77          20 : PiePositionHelper::PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset )
      78             :         : PolarPlottingPositionHelper(eNormalAxis)
      79          20 :         , m_fRingDistance(0.0)
      80             : {
      81          20 :     m_fRadiusOffset = 0.0;
      82          20 :     m_fAngleDegreeOffset = fAngleDegreeOffset;
      83          20 : }
      84             : 
      85          40 : PiePositionHelper::~PiePositionHelper()
      86             : {
      87          40 : }
      88             : 
      89         152 : bool PiePositionHelper::getInnerAndOuterRadius( double fCategoryX
      90             :                                                , double& fLogicInnerRadius, double& fLogicOuterRadius
      91             :                                                , bool bUseRings, double fMaxOffset ) const
      92             : {
      93         152 :     if( !bUseRings )
      94         152 :         fCategoryX = 1.0;
      95             : 
      96         152 :     bool bIsVisible = true;
      97         152 :     double fLogicInner = fCategoryX -0.5+m_fRingDistance/2.0;
      98         152 :     double fLogicOuter = fCategoryX +0.5-m_fRingDistance/2.0;
      99             : 
     100         152 :     if( !isMathematicalOrientationRadius() )
     101             :     {
     102             :         //in this case the given getMaximumX() was not corrcect instead the minimum should have been smaller by fMaxOffset
     103             :         //but during getMaximumX and getMimumX we do not know the axis orientation
     104          80 :         fLogicInner += fMaxOffset;
     105          80 :         fLogicOuter += fMaxOffset;
     106             :     }
     107             : 
     108         152 :     if( fLogicInner >= getLogicMaxX() )
     109           0 :         return false;
     110         152 :     if( fLogicOuter <= getLogicMinX() )
     111           0 :         return false;
     112             : 
     113         152 :     if( fLogicInner < getLogicMinX() )
     114           0 :         fLogicInner = getLogicMinX();
     115         152 :     if( fLogicOuter > getLogicMaxX() )
     116           0 :         fLogicOuter = getLogicMaxX();
     117             : 
     118         152 :     fLogicInnerRadius = fLogicInner;
     119         152 :     fLogicOuterRadius = fLogicOuter;
     120         152 :     if( !isMathematicalOrientationRadius() )
     121          80 :         std::swap(fLogicInnerRadius,fLogicOuterRadius);
     122         152 :     return bIsVisible;
     123             : }
     124             : 
     125          20 : PieChart::PieChart( const uno::Reference<XChartType>& xChartTypeModel
     126             :                    , sal_Int32 nDimensionCount
     127             :                    , bool bExcludingPositioning )
     128             :         : VSeriesPlotter( xChartTypeModel, nDimensionCount )
     129          20 :         , m_pPosHelper( new PiePositionHelper( NormalAxis_Z, (m_nDimension==3)?0.0:90.0 ) )
     130             :         , m_bUseRings(false)
     131          40 :         , m_bSizeExcludesLabelsAndExplodedSegments(bExcludingPositioning)
     132             : {
     133          20 :     ::rtl::math::setNan(&m_fMaxOffset);
     134             : 
     135          20 :     PlotterBase::m_pPosHelper = m_pPosHelper;
     136          20 :     VSeriesPlotter::m_pMainPosHelper = m_pPosHelper;
     137          20 :     m_pPosHelper->m_fRadiusOffset = 0.0;
     138          20 :     m_pPosHelper->m_fRingDistance = 0.0;
     139             : 
     140          20 :     uno::Reference< beans::XPropertySet > xChartTypeProps( xChartTypeModel, uno::UNO_QUERY );
     141          20 :     if( xChartTypeProps.is() ) try
     142             :     {
     143          20 :         xChartTypeProps->getPropertyValue( "UseRings") >>= m_bUseRings;
     144          20 :         if( m_bUseRings )
     145             :         {
     146           0 :             m_pPosHelper->m_fRadiusOffset = 1.0;
     147           0 :             if( nDimensionCount==3 )
     148           0 :                 m_pPosHelper->m_fRingDistance = 0.1;
     149             :         }
     150             :     }
     151           0 :     catch( const uno::Exception& e )
     152             :     {
     153             :         ASSERT_EXCEPTION( e );
     154          20 :     }
     155          20 : }
     156             : 
     157          60 : PieChart::~PieChart()
     158             : {
     159          20 :     delete m_pPosHelper;
     160          40 : }
     161             : 
     162          20 : void PieChart::setScales( const std::vector< ExplicitScaleData >& rScales, bool /* bSwapXAndYAxis */ )
     163             : {
     164             :     OSL_ENSURE(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence");
     165          20 :     m_pPosHelper->setScales( rScales, true );
     166          20 : }
     167             : 
     168          20 : drawing::Direction3D PieChart::getPreferredDiagramAspectRatio() const
     169             : {
     170          20 :     if( m_nDimension == 3 )
     171           2 :         return drawing::Direction3D(1,1,0.10);
     172          18 :     return drawing::Direction3D(1,1,1);
     173             : }
     174             : 
     175           0 : bool PieChart::keepAspectRatio() const
     176             : {
     177           0 :     if( m_nDimension == 3 )
     178           0 :         return false;
     179           0 :     return true;
     180             : }
     181             : 
     182          20 : bool PieChart::shouldSnapRectToUsedArea()
     183             : {
     184          20 :     return true;
     185             : }
     186             : 
     187         152 : uno::Reference< drawing::XShape > PieChart::createDataPoint(
     188             :     const uno::Reference<drawing::XShapes>& xTarget,
     189             :     const uno::Reference<beans::XPropertySet>& xObjectProperties,
     190             :     tPropertyNameValueMap* pOverwritePropertiesMap,
     191             :     const ShapeParam& rParam )
     192             : {
     193             :     //transform position:
     194         152 :     drawing::Direction3D aOffset;
     195         152 :     if (!::rtl::math::approxEqual(rParam.mfExplodePercentage, 0.0))
     196             :     {
     197           0 :         double fAngle  = rParam.mfUnitCircleStartAngleDegree + rParam.mfUnitCircleWidthAngleDegree/2.0;
     198           0 :         double fRadius = (rParam.mfUnitCircleOuterRadius-rParam.mfUnitCircleInnerRadius)*rParam.mfExplodePercentage;
     199           0 :         drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene(0, 0, rParam.mfLogicZ);
     200           0 :         drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene(fAngle, fRadius, rParam.mfLogicZ);
     201           0 :         aOffset = aNewOrigin - aOrigin;
     202             :     }
     203             : 
     204             :     //create point
     205         152 :     uno::Reference< drawing::XShape > xShape(0);
     206         152 :     if(m_nDimension==3)
     207             :     {
     208          64 :         xShape = m_pShapeFactory->createPieSegment( xTarget
     209             :             , rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
     210             :             , rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius
     211          32 :             , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() )
     212          32 :             , rParam.mfDepth );
     213             :     }
     214             :     else
     215             :     {
     216         408 :         xShape = m_pShapeFactory->createPieSegment2D( xTarget
     217             :             , rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
     218             :             , rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius
     219         408 :             , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) );
     220             :     }
     221         152 :     this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), pOverwritePropertiesMap );
     222         152 :     return xShape;
     223             : }
     224             : 
     225         152 : void PieChart::createTextLabelShape(
     226             :     const uno::Reference<drawing::XShapes>& xTextTarget,
     227             :     VDataSeries& rSeries, sal_Int32 nPointIndex, ShapeParam& rParam )
     228             : {
     229         152 :     if (!rSeries.getDataPointLabelIfLabel(nPointIndex))
     230             :         // There is no text label for this data point.  Nothing to do.
     231         276 :         return;
     232             : 
     233          28 :     if (!rtl::math::approxEqual(rParam.mfExplodePercentage, 0.0))
     234             :     {
     235           0 :         double fExplodeOffset = (rParam.mfUnitCircleOuterRadius-rParam.mfUnitCircleInnerRadius)*rParam.mfExplodePercentage;
     236           0 :         rParam.mfUnitCircleInnerRadius += fExplodeOffset;
     237           0 :         rParam.mfUnitCircleOuterRadius += fExplodeOffset;
     238             :     }
     239             : 
     240             :     sal_Int32 nLabelPlacement = rSeries.getLabelPlacement(
     241          28 :         nPointIndex, m_xChartTypeModel, m_nDimension, m_pPosHelper->isSwapXAndY());
     242             : 
     243             :     // AVOID_OVERLAP is in fact "Best fit" in the UI.
     244          28 :     bool bMovementAllowed = ( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::AVOID_OVERLAP );
     245          28 :     if( bMovementAllowed )
     246             :         // Use center for "Best fit" for now. In the future we
     247             :         // may want to implement a real best fit algorithm.
     248             :         // But center is good enough, and close to what Excel
     249             :         // does.
     250          16 :         nLabelPlacement = ::com::sun::star::chart::DataLabelPlacement::CENTER;
     251             : 
     252          28 :     LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
     253          28 :     sal_Int32 nScreenValueOffsetInRadiusDirection = 0 ;
     254          28 :     if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE )
     255           0 :         nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? 150 : 0;//todo maybe calculate this font height dependent
     256          28 :     else if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::INSIDE )
     257           0 :         nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? -150 : 0;//todo maybe calculate this font height dependent
     258             : 
     259          28 :     PolarLabelPositionHelper aPolarPosHelper(m_pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
     260             :     awt::Point aScreenPosition2D(
     261             :         aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(eAlignment, nLabelPlacement
     262             :         , rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
     263          28 :         , rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius, rParam.mfLogicZ+0.5, 0 ));
     264             : 
     265          56 :     PieLabelInfo aPieLabelInfo;
     266          28 :     aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y );
     267          28 :     awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, rParam.mfLogicZ+1.0 ) ) );
     268          28 :     aPieLabelInfo.aOrigin = basegfx::B2IVector( aOrigin.X, aOrigin.Y );
     269             : 
     270             :     //add a scaling independent Offset if requested
     271          28 :     if( nScreenValueOffsetInRadiusDirection != 0)
     272             :     {
     273           0 :         basegfx::B2IVector aDirection( aScreenPosition2D.X- aOrigin.X, aScreenPosition2D.Y- aOrigin.Y );
     274           0 :         aDirection.setLength(nScreenValueOffsetInRadiusDirection);
     275           0 :         aScreenPosition2D.X += aDirection.getX();
     276           0 :         aScreenPosition2D.Y += aDirection.getY();
     277             :     }
     278             : 
     279          28 :     double nVal = rSeries.getYValue(nPointIndex);
     280          56 :     aPieLabelInfo.xTextShape = createDataLabel(
     281          28 :         xTextTarget, rSeries, nPointIndex, nVal, rParam.mfLogicYSum, aScreenPosition2D, eAlignment);
     282             : 
     283          56 :     uno::Reference< container::XChild > xChild( aPieLabelInfo.xTextShape, uno::UNO_QUERY );
     284          28 :     if( xChild.is() )
     285          28 :         aPieLabelInfo.xLabelGroupShape = uno::Reference<drawing::XShape>( xChild->getParent(), uno::UNO_QUERY );
     286          28 :     aPieLabelInfo.fValue = nVal;
     287          28 :     aPieLabelInfo.bMovementAllowed = bMovementAllowed;
     288          28 :     aPieLabelInfo.bMoved= false;
     289          28 :     aPieLabelInfo.xTextTarget = xTextTarget;
     290          56 :     m_aLabelInfoList.push_back(aPieLabelInfo);
     291             : }
     292             : 
     293          42 : void PieChart::addSeries( VDataSeries* pSeries, sal_Int32 /* zSlot */, sal_Int32 /* xSlot */, sal_Int32 /* ySlot */ )
     294             : {
     295          42 :     VSeriesPlotter::addSeries( pSeries, 0, -1, 0 );
     296          42 : }
     297             : 
     298          20 : double PieChart::getMinimumX()
     299             : {
     300          20 :     return 0.5;
     301             : }
     302         172 : double PieChart::getMaxOffset()
     303             : {
     304         172 :     if (!::rtl::math::isNan(m_fMaxOffset))
     305             :         // Value already cached.  Use it.
     306         112 :         return m_fMaxOffset;
     307             : 
     308          60 :     m_fMaxOffset = 0.0;
     309          60 :     if( m_aZSlots.size()<=0 )
     310           0 :         return m_fMaxOffset;
     311          60 :     if( m_aZSlots[0].size()<=0 )
     312           0 :         return m_fMaxOffset;
     313             : 
     314          60 :     const ::std::vector< VDataSeries* >& rSeriesList( m_aZSlots[0][0].m_aSeriesVector );
     315          60 :     if( rSeriesList.size()<=0 )
     316           0 :         return m_fMaxOffset;
     317             : 
     318          60 :     VDataSeries* pSeries = rSeriesList[0];
     319          60 :     uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() );
     320          60 :     if( !xSeriesProp.is() )
     321           0 :         return m_fMaxOffset;
     322             : 
     323          60 :     double fExplodePercentage=0.0;
     324          60 :     xSeriesProp->getPropertyValue( "Offset") >>= fExplodePercentage;
     325          60 :     if(fExplodePercentage>m_fMaxOffset)
     326           0 :         m_fMaxOffset=fExplodePercentage;
     327             : 
     328          60 :     if(!m_bSizeExcludesLabelsAndExplodedSegments)
     329             :     {
     330          60 :         uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
     331          60 :         if( xSeriesProp->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList )
     332             :         {
     333         228 :             for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
     334             :             {
     335         108 :                 uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint(aAttributedDataPointIndexList[nN]) );
     336         108 :                 if(xPointProp.is())
     337             :                 {
     338         108 :                     fExplodePercentage=0.0;
     339         108 :                     xPointProp->getPropertyValue( "Offset") >>= fExplodePercentage;
     340         108 :                     if(fExplodePercentage>m_fMaxOffset)
     341           0 :                         m_fMaxOffset=fExplodePercentage;
     342             :                 }
     343         108 :             }
     344          60 :         }
     345             :     }
     346          60 :     return m_fMaxOffset;
     347             : }
     348          20 : double PieChart::getMaximumX()
     349             : {
     350          20 :     double fMaxOffset = getMaxOffset();
     351          20 :     if( m_aZSlots.size()>0 && m_bUseRings)
     352           0 :         return m_aZSlots[0].size()+0.5+fMaxOffset;
     353          20 :     return 1.5+fMaxOffset;
     354             : }
     355          20 : double PieChart::getMinimumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
     356             : {
     357          20 :     return 0.0;
     358             : }
     359             : 
     360          20 : double PieChart::getMaximumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
     361             : {
     362          20 :     return 1.0;
     363             : }
     364             : 
     365          42 : bool PieChart::isExpandBorderToIncrementRhythm( sal_Int32 /* nDimensionIndex */ )
     366             : {
     367          42 :     return false;
     368             : }
     369             : 
     370          42 : bool PieChart::isExpandIfValuesCloseToBorder( sal_Int32 /* nDimensionIndex */ )
     371             : {
     372          42 :     return false;
     373             : }
     374             : 
     375          42 : bool PieChart::isExpandWideValuesToZero( sal_Int32 /* nDimensionIndex */ )
     376             : {
     377          42 :     return false;
     378             : }
     379             : 
     380          42 : bool PieChart::isExpandNarrowValuesTowardZero( sal_Int32 /* nDimensionIndex */ )
     381             : {
     382          42 :     return false;
     383             : }
     384             : 
     385           0 : bool PieChart::isSeparateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ )
     386             : {
     387           0 :     return false;
     388             : }
     389             : 
     390          40 : void PieChart::createShapes()
     391             : {
     392          40 :     if (m_aZSlots.empty())
     393             :         // No series to plot.
     394           0 :         return;
     395             : 
     396             :     OSL_ENSURE(m_pShapeFactory && m_xLogicTarget.is() && m_xFinalTarget.is(), "PieChart is not properly initialized.");
     397          40 :     if (!m_pShapeFactory || !m_xLogicTarget.is() || !m_xFinalTarget.is())
     398           0 :         return;
     399             : 
     400             :     //the text labels should be always on top of the other series shapes
     401             :     //therefore create an own group for the texts to move them to front
     402             :     //(because the text group is created after the series group the texts are displayed on top)
     403             :     uno::Reference< drawing::XShapes > xSeriesTarget(
     404          40 :         createGroupShape( m_xLogicTarget,OUString() ));
     405             :     uno::Reference< drawing::XShapes > xTextTarget(
     406          80 :         m_pShapeFactory->createGroup2D( m_xFinalTarget,OUString() ));
     407             :     //check necessary here that different Y axis can not be stacked in the same group? ... hm?
     408             : 
     409          40 :     ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = m_aZSlots[0].begin();
     410          40 :     const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = m_aZSlots[0].end();
     411             : 
     412          40 :     ::std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
     413          40 :     if( m_pPosHelper->isMathematicalOrientationRadius() && m_bUseRings )
     414           0 :         nExplodeableSlot = m_aZSlots[0].size()-1;
     415             : 
     416          40 :     m_aLabelInfoList.clear();
     417          40 :     ::rtl::math::setNan(&m_fMaxOffset);
     418          40 :     sal_Int32 n3DRelativeHeight = 100;
     419          80 :     uno::Reference< beans::XPropertySet > xPropertySet( m_xChartTypeModel, uno::UNO_QUERY );
     420          40 :     if ( (m_nDimension==3) && xPropertySet.is())
     421             :     {
     422             :         try
     423             :         {
     424           4 :             uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" );
     425           4 :             aAny >>= n3DRelativeHeight;
     426             :         }
     427           0 :         catch (const uno::Exception&) { }
     428             :     }
     429             : 
     430          80 :     for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); ++aXSlotIter, fSlotX+=1.0 )
     431             :     {
     432          40 :         ShapeParam aParam;
     433             : 
     434          40 :         ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
     435          40 :         if( pSeriesList->size()<=0 )//there should be only one series in each x slot
     436           0 :             continue;
     437          40 :         VDataSeries* pSeries = (*pSeriesList)[0];
     438          40 :         if(!pSeries)
     439           0 :             continue;
     440             : 
     441          40 :         bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
     442             : 
     443             :         // Counter-clockwise offset from the 3 o'clock position.
     444          40 :         m_pPosHelper->m_fAngleDegreeOffset = pSeries->getStartingAngle();
     445             : 
     446             :         //iterate through all points to get the sum
     447          40 :         sal_Int32 nPointIndex=0;
     448          40 :         sal_Int32 nPointCount=pSeries->getTotalPointCount();
     449         192 :         for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
     450             :         {
     451         152 :             double fY = pSeries->getYValue( nPointIndex );
     452             :             if(fY<0.0)
     453             :             {
     454             :                 //@todo warn somehow that negative values are treated as positive
     455             :             }
     456         152 :             if( ::rtl::math::isNan(fY) )
     457           0 :                 continue;
     458         152 :             aParam.mfLogicYSum += fabs(fY);
     459             :         }
     460             : 
     461          40 :         if (aParam.mfLogicYSum == 0.0)
     462             :             // Total sum of all Y values in this series is zero. Skip the whole series.
     463           0 :             continue;
     464             : 
     465          40 :         double fLogicYForNextPoint = 0.0;
     466             :         //iterate through all points to create shapes
     467         192 :         for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
     468             :         {
     469             :             double fLogicInnerRadius, fLogicOuterRadius;
     470         152 :             double fOffset = getMaxOffset();
     471         152 :             bool bIsVisible = m_pPosHelper->getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
     472         152 :             if( !bIsVisible )
     473           0 :                 continue;
     474             : 
     475         152 :             aParam.mfDepth  = this->getTransformedDepth() * (n3DRelativeHeight / 100.0);
     476             : 
     477         152 :             uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
     478             :             //collect data point information (logic coordinates, style ):
     479         152 :             double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
     480         152 :             if( ::rtl::math::isNan(fLogicYValue) )
     481           0 :                 continue;
     482         152 :             if(fLogicYValue==0.0)//@todo: continue also if the resolution to small
     483           0 :                 continue;
     484         152 :             double fLogicYPos = fLogicYForNextPoint;
     485         152 :             fLogicYForNextPoint += fLogicYValue;
     486             : 
     487         304 :             uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
     488             : 
     489             :             //iterate through all subsystems to create partial points
     490             :             {
     491             :                 //logic values on angle axis:
     492         152 :                 double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum;
     493         152 :                 double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / aParam.mfLogicYSum;
     494             : 
     495         152 :                 aParam.mfExplodePercentage = 0.0;
     496         152 :                 bool bDoExplode = ( nExplodeableSlot == static_cast< ::std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
     497         152 :                 if(bDoExplode) try
     498             :                 {
     499         152 :                     xPointProperties->getPropertyValue( "Offset") >>= aParam.mfExplodePercentage;
     500             :                 }
     501           0 :                 catch( const uno::Exception& e )
     502             :                 {
     503             :                     ASSERT_EXCEPTION( e );
     504             :                 }
     505             : 
     506             :                 //transforme to unit circle:
     507         152 :                 aParam.mfUnitCircleWidthAngleDegree = m_pPosHelper->getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
     508         152 :                 aParam.mfUnitCircleStartAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicStartAngleValue );
     509         152 :                 aParam.mfUnitCircleInnerRadius = m_pPosHelper->transformToRadius( fLogicInnerRadius );
     510         152 :                 aParam.mfUnitCircleOuterRadius = m_pPosHelper->transformToRadius( fLogicOuterRadius );
     511             : 
     512             :                 //point color:
     513         152 :                 boost::scoped_ptr< tPropertyNameValueMap > apOverwritePropertiesMap(NULL);
     514         152 :                 if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
     515             :                 {
     516          80 :                     apOverwritePropertiesMap.reset( new tPropertyNameValueMap() );
     517         160 :                     (*apOverwritePropertiesMap)["FillColor"] = uno::makeAny(
     518         160 :                         m_xColorScheme->getColorByIndex( nPointIndex ));
     519             :                 }
     520             : 
     521             :                 //create data point
     522         152 :                 aParam.mfLogicZ = -1.0; // For 3D pie chart label position
     523             :                 uno::Reference<drawing::XShape> xPointShape =
     524             :                     createDataPoint(
     525         304 :                         xSeriesGroupShape_Shapes, xPointProperties, apOverwritePropertiesMap.get(), aParam);
     526             : 
     527         152 :                 if(bHasFillColorMapping)
     528             :                 {
     529           0 :                     double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
     530           0 :                     if(!rtl::math::isNan(nPropVal))
     531             :                     {
     532           0 :                         uno::Reference< beans::XPropertySet > xProps( xPointShape, uno::UNO_QUERY_THROW );
     533           0 :                         xProps->setPropertyValue("FillColor", uno::makeAny(static_cast<sal_Int32>( nPropVal)));
     534             :                     }
     535             :                 }
     536             : 
     537             :                 //create label
     538         152 :                 createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam);
     539             : 
     540         152 :                 if(!bDoExplode)
     541             :                 {
     542             :                     AbstractShapeFactory::setShapeName( xPointShape
     543           0 :                                 , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) );
     544             :                 }
     545             :                 else try
     546             :                 {
     547             :                     //enable dragging of outer segments
     548             : 
     549         152 :                     double fAngle  = aParam.mfUnitCircleStartAngleDegree + aParam.mfUnitCircleWidthAngleDegree/2.0;
     550         152 :                     double fMaxDeltaRadius = aParam.mfUnitCircleOuterRadius-aParam.mfUnitCircleInnerRadius;
     551         152 :                     drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ );
     552         152 :                     drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius + fMaxDeltaRadius, aParam.mfLogicZ );
     553             : 
     554         152 :                     sal_Int32 nOffsetPercent( static_cast<sal_Int32>(aParam.mfExplodePercentage * 100.0) );
     555             : 
     556             :                     awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
     557         152 :                         aOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
     558             :                     awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
     559         152 :                         aNewOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
     560             : 
     561             :                     //enable draging of piesegments
     562             :                     OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
     563             :                         , pSeries->getSeriesParticle()
     564         152 :                         , ObjectIdentifier::getPieSegmentDragMethodServiceName()
     565             :                         , ObjectIdentifier::createPieSegmentDragParameterString(
     566             :                             nOffsetPercent, aMinimumPosition, aMaximumPosition )
     567         304 :                         ) );
     568             : 
     569             :                     AbstractShapeFactory::setShapeName( xPointShape
     570         152 :                                 , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) );
     571             :                 }
     572           0 :                 catch( const uno::Exception& e )
     573             :                 {
     574             :                     ASSERT_EXCEPTION( e );
     575         152 :                 }
     576             :             }//next series in x slot (next y slot)
     577         152 :         }//next category
     578          40 :     }//next x slot
     579             : }
     580             : 
     581             : namespace
     582             : {
     583             : 
     584          42 : ::basegfx::B2IRectangle lcl_getRect( const uno::Reference< drawing::XShape >& xShape )
     585             : {
     586          42 :     ::basegfx::B2IRectangle aRect;
     587          42 :     if( xShape.is() )
     588          42 :         aRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),xShape->getSize() );
     589          42 :     return aRect;
     590             : }
     591             : 
     592           0 : bool lcl_isInsidePage( const awt::Point& rPos, const awt::Size& rSize, const awt::Size& rPageSize )
     593             : {
     594           0 :     if( rPos.X < 0  || rPos.Y < 0 )
     595           0 :         return false;
     596           0 :     if( (rPos.X + rSize.Width) > rPageSize.Width  )
     597           0 :         return false;
     598           0 :     if( (rPos.Y + rSize.Height) > rPageSize.Height )
     599           0 :         return false;
     600           0 :     return true;
     601             : }
     602             : 
     603             : }//end anonymous namespace
     604             : 
     605          28 : PieChart::PieLabelInfo::PieLabelInfo()
     606             :     : xTextShape(0), xLabelGroupShape(0), aFirstPosition(), aOrigin(), fValue(0.0)
     607          28 :     , bMovementAllowed(false), bMoved(false), xTextTarget(0), pPrevious(0),pNext(0)
     608             : {
     609          28 : }
     610             : 
     611           0 : bool PieChart::PieLabelInfo::moveAwayFrom( const PieChart::PieLabelInfo* pFix, const awt::Size& rPageSize, bool bMoveHalfWay, bool bMoveClockwise, bool bAlternativeMoveDirection )
     612             : {
     613             :     //return true if the move was successful
     614           0 :     if(!this->bMovementAllowed)
     615           0 :         return false;
     616             : 
     617           0 :     const sal_Int32 nLabelDistanceX = rPageSize.Width/50;
     618           0 :     const sal_Int32 nLabelDistanceY = rPageSize.Height/50;
     619             : 
     620           0 :     ::basegfx::B2IRectangle aOverlap( lcl_getRect( this->xLabelGroupShape ) );
     621           0 :     aOverlap.intersect( lcl_getRect( pFix->xLabelGroupShape ) );
     622           0 :     if( !aOverlap.isEmpty() )
     623             :     {
     624             :         (void)bAlternativeMoveDirection;//todo
     625             : 
     626           0 :         basegfx::B2IVector aRadiusDirection = this->aFirstPosition - this->aOrigin;
     627           0 :         aRadiusDirection.setLength(1.0);
     628           0 :         basegfx::B2IVector aTangentialDirection( -aRadiusDirection.getY(), aRadiusDirection.getX() );
     629           0 :         bool bShiftHorizontal = abs(aTangentialDirection.getX()) > abs(aTangentialDirection.getY());
     630             : 
     631           0 :         sal_Int32 nShift = bShiftHorizontal ? static_cast<sal_Int32>(aOverlap.getWidth()) : static_cast<sal_Int32>(aOverlap.getHeight());
     632           0 :         nShift += (bShiftHorizontal ? nLabelDistanceX : nLabelDistanceY);
     633           0 :         if( bMoveHalfWay )
     634           0 :             nShift/=2;
     635           0 :         if(!bMoveClockwise)
     636           0 :             nShift*=-1;
     637           0 :         awt::Point aOldPos( this->xLabelGroupShape->getPosition() );
     638           0 :         basegfx::B2IVector aNewPos = basegfx::B2IVector( aOldPos.X, aOldPos.Y ) + nShift*aTangentialDirection;
     639             : 
     640             :         //check whether the new position is ok
     641           0 :         awt::Point aNewAWTPos( aNewPos.getX(), aNewPos.getY() );
     642           0 :         if( !lcl_isInsidePage( aNewAWTPos, this->xLabelGroupShape->getSize(), rPageSize ) )
     643           0 :             return false;
     644             : 
     645           0 :         this->xLabelGroupShape->setPosition( aNewAWTPos );
     646           0 :         this->bMoved = true;
     647             :     }
     648           0 :     return true;
     649             : }
     650             : 
     651           0 : void PieChart::resetLabelPositionsToPreviousState()
     652             : {
     653           0 :     std::vector< PieLabelInfo >::iterator aIt = m_aLabelInfoList.begin();
     654           0 :     std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
     655           0 :     for( ;aIt!=aEnd; ++aIt )
     656           0 :         aIt->xLabelGroupShape->setPosition(aIt->aPreviousPosition);
     657           0 : }
     658             : 
     659           4 : bool PieChart::detectLabelOverlapsAndMove( const awt::Size& rPageSize )
     660             : {
     661             :     //returns true when there might be more to do
     662             : 
     663             :     //find borders of a group of overlapping labels
     664           4 :     bool bOverlapFound = false;
     665           4 :     PieLabelInfo* pStart = &(*(m_aLabelInfoList.rbegin()));
     666           4 :     PieLabelInfo* pFirstBorder = 0;
     667           4 :     PieLabelInfo* pSecondBorder = 0;
     668           4 :     PieLabelInfo* pCurrent = pStart;
     669          14 :     do
     670             :     {
     671          14 :         ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
     672          14 :         ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
     673          14 :         aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
     674          14 :         aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
     675             : 
     676          14 :         bool bPreviousOverlap = !aPreviousOverlap.isEmpty();
     677          14 :         bool bNextOverlap = !aNextOverlap.isEmpty();
     678          14 :         if( bPreviousOverlap || bNextOverlap )
     679           0 :             bOverlapFound = true;
     680          14 :         if( !bPreviousOverlap && bNextOverlap )
     681             :         {
     682           0 :             pFirstBorder = pCurrent;
     683           0 :             break;
     684             :         }
     685          14 :         pCurrent = pCurrent->pNext;
     686             :     }
     687             :     while( pCurrent != pStart );
     688             : 
     689           4 :     if( !bOverlapFound )
     690           4 :         return false;
     691             : 
     692           0 :     if( pFirstBorder )
     693             :     {
     694           0 :         pCurrent = pFirstBorder;
     695           0 :         do
     696             :         {
     697           0 :             ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
     698           0 :             ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
     699           0 :             aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
     700           0 :             aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
     701             : 
     702           0 :             if( !aPreviousOverlap.isEmpty() && aNextOverlap.isEmpty() )
     703             :             {
     704           0 :                 pSecondBorder = pCurrent;
     705           0 :                 break;
     706             :             }
     707           0 :             pCurrent = pCurrent->pNext;
     708             :         }
     709             :         while( pCurrent != pFirstBorder );
     710             :     }
     711             : 
     712           0 :     if( !pFirstBorder || !pSecondBorder )
     713             :     {
     714           0 :         pFirstBorder = &(*(m_aLabelInfoList.rbegin()));
     715           0 :         pSecondBorder = &(*(m_aLabelInfoList.begin()));
     716             :     }
     717             : 
     718             :     //find center
     719           0 :     PieLabelInfo* pCenter = pFirstBorder;
     720           0 :     sal_Int32 nOverlapGroupCount = 1;
     721           0 :     for( pCurrent = pFirstBorder ;pCurrent != pSecondBorder; pCurrent = pCurrent->pNext )
     722           0 :         nOverlapGroupCount++;
     723           0 :     sal_Int32 nCenterPos = nOverlapGroupCount/2;
     724           0 :     bool bSingleCenter = nOverlapGroupCount%2 != 0;
     725           0 :     if( bSingleCenter )
     726           0 :         nCenterPos++;
     727           0 :     if(nCenterPos>1)
     728             :     {
     729           0 :         pCurrent = pFirstBorder;
     730           0 :         while( --nCenterPos )
     731           0 :             pCurrent = pCurrent->pNext;
     732           0 :         pCenter = pCurrent;
     733             :     }
     734             : 
     735             :     //remind current positions
     736           0 :     pCurrent = pStart;
     737           0 :     do
     738             :     {
     739           0 :         pCurrent->aPreviousPosition = pCurrent->xLabelGroupShape->getPosition();
     740           0 :         pCurrent = pCurrent->pNext;
     741             :     }
     742             :     while( pCurrent != pStart );
     743             : 
     744           0 :     bool bAlternativeMoveDirection = false;
     745           0 :     if( !tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize ) )
     746           0 :         tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize );
     747           0 :     return true;
     748             : }
     749             : 
     750           0 : bool PieChart::tryMoveLabels( PieLabelInfo* pFirstBorder, PieLabelInfo* pSecondBorder
     751             :                              , PieLabelInfo* pCenter
     752             :                              , bool bSingleCenter, bool& rbAlternativeMoveDirection, const awt::Size& rPageSize )
     753             : {
     754           0 :     PieLabelInfo* p1 = bSingleCenter ? pCenter->pPrevious : pCenter;
     755           0 :     PieLabelInfo* p2 = pCenter->pNext;
     756             :     //return true when successful
     757             : 
     758           0 :     bool bLabelOrderIsAntiClockWise = m_pPosHelper->isMathematicalOrientationAngle();
     759             : 
     760           0 :     PieLabelInfo* pCurrent = 0;
     761           0 :     for( pCurrent = p2 ;pCurrent->pPrevious != pSecondBorder; pCurrent = pCurrent->pNext )
     762             :     {
     763           0 :         PieLabelInfo* pFix = 0;
     764           0 :         for( pFix = p2->pPrevious ;pFix != pCurrent; pFix = pFix->pNext )
     765             :         {
     766           0 :             if( !pCurrent->moveAwayFrom( pFix, rPageSize, !bSingleCenter && pCurrent == p2, !bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
     767             :             {
     768           0 :                 if( !rbAlternativeMoveDirection )
     769             :                 {
     770           0 :                     rbAlternativeMoveDirection = true;
     771           0 :                     resetLabelPositionsToPreviousState();
     772           0 :                     return false;
     773             :                 }
     774             :             }
     775             :         }
     776             :     }
     777           0 :     for( pCurrent = p1 ;pCurrent->pNext != pFirstBorder; pCurrent = pCurrent->pPrevious )
     778             :     {
     779           0 :         PieLabelInfo* pFix = 0;
     780           0 :         for( pFix = p2->pNext ;pFix != pCurrent; pFix = pFix->pPrevious )
     781             :         {
     782           0 :             if( !pCurrent->moveAwayFrom( pFix, rPageSize, false, bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
     783             :             {
     784           0 :                 if( !rbAlternativeMoveDirection )
     785             :                 {
     786           0 :                     rbAlternativeMoveDirection = true;
     787           0 :                     resetLabelPositionsToPreviousState();
     788           0 :                     return false;
     789             :                 }
     790             :             }
     791             :         }
     792             :     }
     793           0 :     return true;
     794             : }
     795             : 
     796          20 : void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSize )
     797             : {
     798             :     //check whether there are any labels that should be moved
     799          20 :     std::vector< PieLabelInfo >::iterator aIt1 = m_aLabelInfoList.begin();
     800          20 :     std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
     801          20 :     bool bMoveableFound = false;
     802          24 :     for( ;aIt1!=aEnd; ++aIt1 )
     803             :     {
     804           8 :         if(aIt1->bMovementAllowed)
     805             :         {
     806           4 :             bMoveableFound = true;
     807           4 :             break;
     808             :         }
     809             :     }
     810          20 :     if(!bMoveableFound)
     811          32 :         return;
     812             : 
     813           4 :     double fPageDiagonaleLength = sqrt( double( rPageSize.Width*rPageSize.Width + rPageSize.Height*rPageSize.Height) );
     814           4 :     if( ::rtl::math::approxEqual( fPageDiagonaleLength, 0.0 ) )
     815           0 :         return;
     816             : 
     817             :     //init next and previous
     818           4 :     aIt1 = m_aLabelInfoList.begin();
     819           4 :     std::vector< PieLabelInfo >::iterator aIt2 = aIt1;
     820           4 :     if( aIt1==aEnd )//no need to do anything when we only have one label
     821           0 :         return;
     822           4 :     aIt1->pPrevious = &(*(m_aLabelInfoList.rbegin()));
     823           4 :     ++aIt2;
     824          14 :     for( ;aIt2!=aEnd; ++aIt1, ++aIt2 )
     825             :     {
     826          10 :         PieLabelInfo& rInfo1( *aIt1 );
     827          10 :         PieLabelInfo& rInfo2( *aIt2 );
     828          10 :         rInfo1.pNext = &rInfo2;
     829          10 :         rInfo2.pPrevious = &rInfo1;
     830             :     }
     831           4 :     aIt1->pNext = &(*(m_aLabelInfoList.begin()));
     832             : 
     833             :     //detect overlaps and move
     834           4 :     sal_Int32 nMaxIterations = 50;
     835           8 :     while( detectLabelOverlapsAndMove( rPageSize ) && nMaxIterations > 0 )
     836           0 :         nMaxIterations--;
     837             : 
     838             :     //create connection lines for the moved labels
     839           4 :     aEnd = m_aLabelInfoList.end();
     840           4 :     VLineProperties aVLineProperties;
     841          18 :     for( aIt1 = m_aLabelInfoList.begin(); aIt1!=aEnd; ++aIt1 )
     842             :     {
     843          14 :         PieLabelInfo& rInfo( *aIt1 );
     844          14 :         if( rInfo.bMoved )
     845             :         {
     846           0 :             sal_Int32 nX1 = rInfo.aFirstPosition.getX();
     847           0 :             sal_Int32 nY1 = rInfo.aFirstPosition.getY();
     848           0 :             sal_Int32 nX2 = nX1;
     849           0 :             sal_Int32 nY2 = nY1;
     850           0 :             ::basegfx::B2IRectangle aRect( lcl_getRect( rInfo.xLabelGroupShape ) );
     851           0 :             if( nX1 < aRect.getMinX() )
     852           0 :                 nX2 = aRect.getMinX();
     853           0 :             else if( nX1 > aRect.getMaxX() )
     854           0 :                 nX2 = aRect.getMaxX();
     855             : 
     856           0 :             if( nY1 < aRect.getMinY() )
     857           0 :                 nY2 = aRect.getMinY();
     858           0 :             else if( nY1 > aRect.getMaxY() )
     859           0 :                 nY2 = aRect.getMaxY();
     860             : 
     861             :             //when the line is very short compared to the page size don't create one
     862           0 :             ::basegfx::B2DVector aLength(nX1-nX2, nY1-nY2);
     863           0 :             if( (aLength.getLength()/fPageDiagonaleLength) < 0.01 )
     864           0 :                 continue;
     865             : 
     866           0 :             drawing::PointSequenceSequence aPoints(1);
     867           0 :             aPoints[0].realloc(2);
     868           0 :             aPoints[0][0].X = nX1;
     869           0 :             aPoints[0][0].Y = nY1;
     870           0 :             aPoints[0][1].X = nX2;
     871           0 :             aPoints[0][1].Y = nY2;
     872             : 
     873           0 :             uno::Reference< beans::XPropertySet > xProp( rInfo.xTextShape, uno::UNO_QUERY);
     874           0 :             if( xProp.is() )
     875             :             {
     876           0 :                 sal_Int32 nColor = 0;
     877           0 :                 xProp->getPropertyValue("CharColor") >>= nColor;
     878           0 :                 if( nColor != -1 )//automatic font color does not work for lines -> fallback to black
     879           0 :                     aVLineProperties.Color = uno::makeAny(nColor);
     880             :             }
     881           0 :             m_pShapeFactory->createLine2D( rInfo.xTextTarget, aPoints, &aVLineProperties );
     882             :         }
     883           4 :     }
     884             : }
     885             : 
     886         108 : } //namespace chart
     887             : 
     888             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10