LCOV - code coverage report
Current view: top level - chart2/source/view/main - VLegend.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 291 449 64.8 %
Date: 2012-08-25 Functions: 18 18 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 275 719 38.2 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*
       3                 :            :  * This file is part of the LibreOffice project.
       4                 :            :  *
       5                 :            :  * This Source Code Form is subject to the terms of the Mozilla Public
       6                 :            :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7                 :            :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8                 :            :  *
       9                 :            :  * This file incorporates work covered by the following license notice:
      10                 :            :  *
      11                 :            :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12                 :            :  *   contributor license agreements. See the NOTICE file distributed
      13                 :            :  *   with this work for additional information regarding copyright
      14                 :            :  *   ownership. The ASF licenses this file to you under the Apache
      15                 :            :  *   License, Version 2.0 (the "License"); you may not use this file
      16                 :            :  *   except in compliance with the License. You may obtain a copy of
      17                 :            :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18                 :            :  */
      19                 :            : 
      20                 :            : #include "VLegend.hxx"
      21                 :            : #include "macros.hxx"
      22                 :            : #include "PropertyMapper.hxx"
      23                 :            : #include "CommonConverters.hxx"
      24                 :            : #include "ObjectIdentifier.hxx"
      25                 :            : #include "RelativePositionHelper.hxx"
      26                 :            : #include "ShapeFactory.hxx"
      27                 :            : #include "RelativeSizeHelper.hxx"
      28                 :            : #include "LegendEntryProvider.hxx"
      29                 :            : #include "chartview/DrawModelWrapper.hxx"
      30                 :            : #include <com/sun/star/text/XTextRange.hpp>
      31                 :            : #include <com/sun/star/text/WritingMode2.hpp>
      32                 :            : #include <com/sun/star/beans/XPropertySet.hpp>
      33                 :            : #include <com/sun/star/beans/XPropertyState.hpp>
      34                 :            : #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
      35                 :            : #include <com/sun/star/drawing/LineJoint.hpp>
      36                 :            : #include <com/sun/star/chart/ChartLegendExpansion.hpp>
      37                 :            : #include <com/sun/star/chart2/LegendPosition.hpp>
      38                 :            : #include <com/sun/star/chart2/RelativePosition.hpp>
      39                 :            : #include <rtl/ustrbuf.hxx>
      40                 :            : #include <svl/languageoptions.hxx>
      41                 :            : 
      42                 :            : #include <vector>
      43                 :            : #include <algorithm>
      44                 :            : 
      45                 :            : using namespace ::com::sun::star;
      46                 :            : using namespace ::com::sun::star::chart2;
      47                 :            : 
      48                 :            : using ::com::sun::star::uno::Reference;
      49                 :            : using ::com::sun::star::uno::Sequence;
      50                 :            : using ::rtl::OUString;
      51                 :            : using ::rtl::OUStringBuffer;
      52                 :            : 
      53                 :            : //.............................................................................
      54                 :            : namespace chart
      55                 :            : {
      56                 :            : //.............................................................................
      57                 :            : 
      58                 :            : namespace
      59                 :            : {
      60                 :            : 
      61                 :            : typedef ::std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues;
      62                 :            : 
      63                 :            : typedef ::std::vector< ViewLegendEntry > tViewLegendEntryContainer;
      64                 :            : 
      65                 :        956 : double lcl_CalcViewFontSize(
      66                 :            :     const Reference< beans::XPropertySet > & xProp,
      67                 :            :     const awt::Size & rReferenceSize )
      68                 :            : {
      69                 :        956 :     double fResult = 10.0;
      70                 :            : 
      71                 :        956 :     awt::Size aPropRefSize;
      72                 :        956 :     float fFontHeight( 0.0 );
      73 [ +  - ][ +  - ]:        956 :     if( xProp.is() && ( xProp->getPropertyValue( C2U( "CharHeight" )) >>= fFontHeight ))
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
           [ +  -  #  #  
           #  # ][ +  - ]
      74                 :            :     {
      75                 :        956 :         fResult = fFontHeight;
      76                 :            :         try
      77                 :            :         {
      78 [ +  - ][ +  - ]:        956 :             if( (xProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) &&
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ +  - ][ +  - ]
           [ -  +  #  #  
             #  #  #  # ]
      79                 :            :                 (aPropRefSize.Height > 0))
      80                 :            :             {
      81         [ #  # ]:          0 :                 fResult = ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize );
      82                 :            :             }
      83                 :            :         }
      84         [ #  # ]:          0 :         catch( const uno::Exception & ex )
      85                 :            :         {
      86                 :            :             ASSERT_EXCEPTION( ex );
      87                 :            :         }
      88                 :            :     }
      89                 :            : 
      90                 :            :     // pt -> 1/100th mm
      91                 :        956 :     return (fResult * (2540.0 / 72.0));
      92                 :            : }
      93                 :            : 
      94                 :        956 : void lcl_getProperties(
      95                 :            :     const Reference< beans::XPropertySet > & xLegendProp,
      96                 :            :     tPropertyValues & rOutLineFillProperties,
      97                 :            :     tPropertyValues & rOutTextProperties,
      98                 :            :     const awt::Size & rReferenceSize )
      99                 :            : {
     100                 :            :     // Get Line- and FillProperties from model legend
     101         [ +  - ]:        956 :     if( xLegendProp.is())
     102                 :            :     {
     103                 :            :         // set rOutLineFillProperties
     104         [ +  - ]:        956 :         ::chart::tPropertyNameValueMap aLineFillValueMap;
     105 [ +  - ][ +  - ]:        956 :         ::chart::PropertyMapper::getValueMap( aLineFillValueMap, ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xLegendProp );
     106                 :            : 
     107 [ +  - ][ +  - ]:        956 :         aLineFillValueMap[ C2U("LineJoint") ] = uno::makeAny( drawing::LineJoint_ROUND );
                 [ +  - ]
     108                 :            : 
     109                 :            :         ::chart::PropertyMapper::getMultiPropertyListsFromValueMap(
     110         [ +  - ]:        956 :             rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap );
     111                 :            : 
     112                 :            :         // set rOutTextProperties
     113         [ +  - ]:        956 :         ::chart::tPropertyNameValueMap aTextValueMap;
     114 [ +  - ][ +  - ]:        956 :         ::chart::PropertyMapper::getValueMap( aTextValueMap, ::chart::PropertyMapper::getPropertyNameMapForCharacterProperties(), xLegendProp );
     115                 :            : 
     116                 :        956 :         drawing::TextHorizontalAdjust eHorizAdjust( drawing::TextHorizontalAdjust_LEFT );
     117 [ +  - ][ +  - ]:        956 :         aTextValueMap[ C2U("TextAutoGrowHeight") ] = uno::makeAny( sal_True );
                 [ +  - ]
     118 [ +  - ][ +  - ]:        956 :         aTextValueMap[ C2U("TextAutoGrowWidth") ] = uno::makeAny( sal_True );
                 [ +  - ]
     119 [ +  - ][ +  - ]:        956 :         aTextValueMap[ C2U("TextHorizontalAdjust") ] = uno::makeAny( eHorizAdjust );
                 [ +  - ]
     120 [ +  - ][ +  - ]:        956 :         aTextValueMap[ C2U("TextMaximumFrameWidth") ] = uno::makeAny( rReferenceSize.Width ); //needs to be overwritten by actual available space in the legend
                 [ +  - ]
     121                 :            : 
     122                 :            :         // recalculate font size
     123                 :        956 :         awt::Size aPropRefSize;
     124                 :        956 :         float fFontHeight( 0.0 );
     125 [ +  - ][ +  - ]:       1912 :         if( (xLegendProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) &&
         [ +  - ][ -  + ]
           [ #  #  #  # ]
         [ +  - ][ +  - ]
           [ -  +  #  #  
           #  # ][ +  - ]
     126                 :            :             (aPropRefSize.Height > 0) &&
     127 [ #  # ][ #  # ]:        956 :             (aTextValueMap[ C2U("CharHeight") ] >>= fFontHeight) )
         [ -  + ][ #  # ]
     128                 :            :         {
     129 [ #  # ][ #  # ]:          0 :             aTextValueMap[ C2U("CharHeight") ] = uno::makeAny(
     130                 :            :                 static_cast< float >(
     131 [ #  # ][ #  # ]:          0 :                     ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )));
     132                 :            : 
     133 [ #  # ][ #  # ]:          0 :             if( aTextValueMap[ C2U("CharHeightAsian") ] >>= fFontHeight )
                 [ #  # ]
     134                 :            :             {
     135 [ #  # ][ #  # ]:          0 :                 aTextValueMap[ C2U("CharHeightAsian") ] = uno::makeAny(
     136                 :            :                     static_cast< float >(
     137 [ #  # ][ #  # ]:          0 :                         ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )));
     138                 :            :             }
     139 [ #  # ][ #  # ]:          0 :             if( aTextValueMap[ C2U("CharHeightComplex") ] >>= fFontHeight )
                 [ #  # ]
     140                 :            :             {
     141 [ #  # ][ #  # ]:          0 :                 aTextValueMap[ C2U("CharHeightComplex") ] = uno::makeAny(
     142                 :            :                     static_cast< float >(
     143 [ #  # ][ #  # ]:          0 :                         ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )));
     144                 :            :             }
     145                 :            :         }
     146                 :            : 
     147                 :            :         ::chart::PropertyMapper::getMultiPropertyListsFromValueMap(
     148         [ +  - ]:        956 :             rOutTextProperties.first, rOutTextProperties.second, aTextValueMap );
     149                 :            :     }
     150                 :        956 : }
     151                 :            : 
     152                 :        956 : awt::Size lcl_createTextShapes(
     153                 :            :     const tViewLegendEntryContainer & rEntries,
     154                 :            :     const Reference< lang::XMultiServiceFactory > & xShapeFactory,
     155                 :            :     const Reference< drawing::XShapes > & xTarget,
     156                 :            :     ::std::vector< Reference< drawing::XShape > > & rOutTextShapes,
     157                 :            :     const tPropertyValues & rTextProperties )
     158                 :            : {
     159                 :        956 :     awt::Size aResult;
     160                 :            : 
     161 [ +  - ][ +  + ]:       8322 :     for( tViewLegendEntryContainer::const_iterator aIt( rEntries.begin());
     162                 :       4161 :          aIt != rEntries.end(); ++aIt )
     163                 :            :     {
     164                 :            :         try
     165                 :            :         {
     166                 :            :             // create label shape
     167                 :            :             Reference< drawing::XShape > xEntry(
     168         [ +  - ]:       3205 :                 xShapeFactory->createInstance(
     169 [ +  - ][ +  - ]:       3205 :                     C2U( "com.sun.star.drawing.TextShape" )), uno::UNO_QUERY_THROW );
                 [ +  - ]
     170 [ +  - ][ +  - ]:       3205 :             xTarget->add( xEntry );
     171                 :            : 
     172                 :            :             // set label text
     173         [ +  - ]:       3205 :             Sequence< Reference< XFormattedString > > aLabelSeq = (*aIt).aLabel;
     174         [ +  + ]:       6410 :             for( sal_Int32 i = 0; i < aLabelSeq.getLength(); ++i )
     175                 :            :             {
     176                 :            :                 // todo: support more than one text range
     177         [ +  - ]:       3205 :                 if( i == 1 )
     178                 :            :                     break;
     179                 :            : 
     180         [ +  - ]:       3205 :                 Reference< text::XTextRange > xRange( xEntry, uno::UNO_QUERY );
     181 [ +  - ][ +  - ]:       3205 :                 OUString aLabelString( aLabelSeq[i]->getString());
                 [ +  - ]
     182                 :            :                 // workaround for Issue #i67540#
     183         [ +  + ]:       3205 :                 if( aLabelString.isEmpty())
     184         [ +  - ]:          7 :                     aLabelString = C2U(" ");
     185         [ +  - ]:       3205 :                 if( xRange.is())
     186 [ +  - ][ +  - ]:       3205 :                     xRange->setString( aLabelString );
     187                 :            : 
     188                 :            :                 PropertyMapper::setMultiProperties(
     189                 :            :                     rTextProperties.first, rTextProperties.second,
     190 [ +  - ][ +  - ]:       3205 :                     Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY ));
     191                 :            : 
     192                 :            :                 // adapt max-extent
     193 [ +  - ][ +  - ]:       3205 :                 awt::Size aCurrSize( xEntry->getSize());
     194         [ +  - ]:       3205 :                 aResult.Width  = ::std::max( aResult.Width,  aCurrSize.Width  );
     195         [ +  - ]:       3205 :                 aResult.Height = ::std::max( aResult.Height, aCurrSize.Height );
     196                 :       3205 :             }
     197                 :            : 
     198 [ +  - ][ +  - ]:       3205 :             rOutTextShapes.push_back( xEntry );
                 [ #  # ]
     199                 :            :         }
     200         [ #  # ]:          0 :         catch( const uno::Exception & ex )
     201                 :            :         {
     202                 :            :             ASSERT_EXCEPTION( ex );
     203                 :            :         }
     204                 :            :     }
     205                 :            : 
     206                 :        956 :     return aResult;
     207                 :            : }
     208                 :            : 
     209                 :        944 : void lcl_collectColumnWidths( std::vector< sal_Int32 >& rColumnWidths, const sal_Int32 nNumberOfRows, const sal_Int32 nNumberOfColumns
     210                 :            :                              , const ::std::vector< Reference< drawing::XShape > > aTextShapes, sal_Int32 nSymbolPlusDistanceWidth )
     211                 :            : {
     212                 :        944 :     rColumnWidths.clear();
     213                 :        944 :     sal_Int32 nRow = 0;
     214                 :        944 :     sal_Int32 nColumn = 0;
     215                 :        944 :     sal_Int32 nNumberOfEntries = aTextShapes.size();
     216         [ +  + ]:       4132 :     for( ; nRow < nNumberOfRows; ++nRow )
     217                 :            :     {
     218         [ +  + ]:       6410 :         for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn )
     219                 :            :         {
     220                 :       3222 :             sal_Int32 nEntry = (nColumn + nRow * nNumberOfColumns);
     221         [ +  + ]:       3222 :             if( nEntry < nNumberOfEntries )
     222                 :            :             {
     223 [ +  - ][ +  - ]:       3205 :                 awt::Size aTextSize( aTextShapes[ nEntry ]->getSize() );
     224                 :       3205 :                 sal_Int32 nWidth = nSymbolPlusDistanceWidth + aTextSize.Width;
     225         [ +  + ]:       3205 :                 if( nRow==0 )
     226         [ +  - ]:        961 :                     rColumnWidths.push_back( nWidth );
     227                 :            :                 else
     228 [ +  - ][ +  - ]:       3205 :                     rColumnWidths[nColumn] = ::std::max( nWidth, rColumnWidths[nColumn] );
                 [ +  - ]
     229                 :            :             }
     230                 :            :         }
     231                 :            :     }
     232                 :        944 : }
     233                 :            : 
     234                 :        944 : void lcl_collectRowHeighs( std::vector< sal_Int32 >& rRowHeights, const sal_Int32 nNumberOfRows, const sal_Int32 nNumberOfColumns
     235                 :            :                           , const ::std::vector< Reference< drawing::XShape > > aTextShapes )
     236                 :            : {
     237                 :            :     // calculate maximum height for each row
     238                 :            :     // and collect column widths
     239                 :        944 :     rRowHeights.clear();
     240                 :        944 :     sal_Int32 nRow = 0;
     241                 :        944 :     sal_Int32 nColumn = 0;
     242                 :        944 :     sal_Int32 nNumberOfEntries = aTextShapes.size();
     243         [ +  + ]:       4132 :     for( ; nRow < nNumberOfRows; ++nRow )
     244                 :            :     {
     245                 :       3188 :         sal_Int32 nCurrentRowHeight = 0;
     246         [ +  + ]:       6410 :         for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn )
     247                 :            :         {
     248                 :       3222 :             sal_Int32 nEntry = (nColumn + nRow * nNumberOfColumns);
     249         [ +  + ]:       3222 :             if( nEntry < nNumberOfEntries )
     250                 :            :             {
     251 [ +  - ][ +  - ]:       3205 :                 awt::Size aTextSize( aTextShapes[ nEntry ]->getSize() );
     252         [ +  - ]:       3205 :                 nCurrentRowHeight = ::std::max( nCurrentRowHeight, aTextSize.Height );
     253                 :            :             }
     254                 :            :         }
     255         [ +  - ]:       3188 :         rRowHeights.push_back( nCurrentRowHeight );
     256                 :            :     }
     257                 :        944 : }
     258                 :            : 
     259                 :        944 : sal_Int32 lcl_getTextLineHeight( const std::vector< sal_Int32 >& aRowHeights, const sal_Int32 nNumberOfRows, double fViewFontSize )
     260                 :            : {
     261                 :        944 :     const sal_Int32 nFontHeight = static_cast< sal_Int32 >( fViewFontSize );
     262                 :        944 :     sal_Int32 nTextLineHeight = nFontHeight;
     263         [ +  - ]:        944 :     for( sal_Int32 nR=0; nR<nNumberOfRows; nR++ )
     264                 :            :     {
     265                 :        944 :         sal_Int32 nFullTextHeight = aRowHeights[ nR ];
     266         [ +  - ]:        944 :         if( ( nFullTextHeight / nFontHeight ) <= 1 )
     267                 :            :         {
     268                 :        944 :             nTextLineHeight = nFullTextHeight;//found an entry with one line-> have real text height
     269                 :        944 :             break;
     270                 :            :         }
     271                 :            :     }
     272                 :        944 :     return nTextLineHeight;
     273                 :            : }
     274                 :            : 
     275                 :            : //returns resulting legend size
     276                 :        956 : awt::Size lcl_placeLegendEntries(
     277                 :            :     tViewLegendEntryContainer & rEntries,
     278                 :            :     ::com::sun::star::chart::ChartLegendExpansion eExpansion,
     279                 :            :     bool bSymbolsLeftSide,
     280                 :            :     double fViewFontSize,
     281                 :            :     const awt::Size& rMaxSymbolExtent,
     282                 :            :     tPropertyValues & rTextProperties,
     283                 :            :     const Reference< drawing::XShapes > & xTarget,
     284                 :            :     const Reference< lang::XMultiServiceFactory > & xShapeFactory,
     285                 :            :     const awt::Size & rAvailableSpace )
     286                 :            : {
     287                 :        956 :     bool bIsCustomSize = (eExpansion == ::com::sun::star::chart::ChartLegendExpansion_CUSTOM);
     288                 :        956 :     awt::Size aResultingLegendSize(0,0);
     289         [ -  + ]:        956 :     if( bIsCustomSize )
     290                 :          0 :         aResultingLegendSize = rAvailableSpace;
     291                 :            : 
     292                 :            :     // #i109336# Improve auto positioning in chart
     293         [ +  - ]:        956 :     sal_Int32 nXPadding = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.33 ) );
     294                 :            :     //sal_Int32 nXPadding = static_cast< sal_Int32 >( std::max( 200.0, fViewFontSize * 0.33 ) );
     295         [ +  - ]:        956 :     sal_Int32 nXOffset  = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.66 ) );
     296         [ +  - ]:        956 :     sal_Int32 nYPadding = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.2 ) );
     297         [ +  - ]:        956 :     sal_Int32 nYOffset  = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.2 ) );
     298                 :            :     //sal_Int32 nYOffset  = static_cast< sal_Int32 >( std::max( 230.0, fViewFontSize * 0.45 ) );
     299                 :            : 
     300         [ +  - ]:        956 :     const sal_Int32 nSymbolToTextDistance = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm
     301                 :        956 :     const sal_Int32 nSymbolPlusDistanceWidth = rMaxSymbolExtent.Width + nSymbolToTextDistance;
     302                 :        956 :     sal_Int32 nMaxTextWidth = rAvailableSpace.Width - (2 * nXPadding) - nSymbolPlusDistanceWidth;
     303         [ +  - ]:        956 :     rtl::OUString aPropNameTextMaximumFrameWidth( C2U("TextMaximumFrameWidth") );
     304         [ +  - ]:        956 :     uno::Any* pFrameWidthAny = PropertyMapper::getValuePointer( rTextProperties.second, rTextProperties.first, aPropNameTextMaximumFrameWidth);
     305         [ +  - ]:        956 :     if(pFrameWidthAny)
     306                 :            :     {
     307         [ +  - ]:        956 :         if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_HIGH )
     308                 :            :         {
     309                 :            :             // limit the width of texts to 30% of the total available width
     310                 :            :             // #i109336# Improve auto positioning in chart
     311                 :        956 :             nMaxTextWidth = rAvailableSpace.Width * 3 / 10;
     312                 :            :         }
     313         [ +  - ]:        956 :         *pFrameWidthAny = uno::makeAny(nMaxTextWidth);
     314                 :            :     }
     315                 :            : 
     316         [ +  - ]:        956 :     ::std::vector< Reference< drawing::XShape > > aTextShapes;
     317         [ +  - ]:        956 :     awt::Size aMaxEntryExtent = lcl_createTextShapes( rEntries, xShapeFactory, xTarget, aTextShapes, rTextProperties );
     318                 :            :     OSL_ASSERT( aTextShapes.size() == rEntries.size());
     319                 :            : 
     320                 :        956 :     sal_Int32 nMaxEntryWidth = nXOffset + nSymbolPlusDistanceWidth + aMaxEntryExtent.Width;
     321                 :        956 :     sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height;
     322                 :        956 :     sal_Int32 nNumberOfEntries = rEntries.size();
     323                 :            : 
     324                 :        956 :     sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0;
     325         [ +  - ]:        956 :     std::vector< sal_Int32 > aColumnWidths;
     326         [ +  - ]:        956 :     std::vector< sal_Int32 > aRowHeights;
     327                 :            : 
     328                 :        956 :     sal_Int32 nTextLineHeight = static_cast< sal_Int32 >( fViewFontSize );
     329                 :            : 
     330                 :            :     // determine layout depending on LegendExpansion
     331         [ -  + ]:        956 :     if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_CUSTOM )
     332                 :            :     {
     333                 :          0 :         sal_Int32 nCurrentRow=0;
     334                 :          0 :         sal_Int32 nCurrentColumn=-1;
     335                 :          0 :         sal_Int32 nMaxColumnCount=-1;
     336         [ #  # ]:          0 :         for( sal_Int32 nN=0; nN<static_cast<sal_Int32>(aTextShapes.size()); nN++ )
     337                 :            :         {
     338                 :          0 :             Reference< drawing::XShape > xShape( aTextShapes[nN] );
     339         [ #  # ]:          0 :             if( !xShape.is() )
     340                 :          0 :                 continue;
     341 [ #  # ][ #  # ]:          0 :             awt::Size aSize( xShape->getSize() );
     342                 :          0 :             sal_Int32 nNewWidth = aSize.Width + nSymbolPlusDistanceWidth;
     343                 :          0 :             sal_Int32 nCurrentColumnCount = aColumnWidths.size();
     344                 :            : 
     345                 :            :             //are we allowed to add a new column?
     346 [ #  # ][ #  # ]:          0 :             if( nMaxColumnCount==-1 || (nCurrentColumn+1) < nMaxColumnCount )
     347                 :            :             {
     348                 :            :                 //try add a new column
     349                 :          0 :                 nCurrentColumn++;
     350         [ #  # ]:          0 :                 if( nCurrentColumn < nCurrentColumnCount )
     351                 :            :                 {
     352                 :            :                     //check whether the current column width is sufficient for the new entry
     353 [ #  # ][ #  # ]:          0 :                     if( aColumnWidths[nCurrentColumn]>=nNewWidth )
     354                 :            :                     {
     355                 :            :                         //all good proceed with next entry
     356                 :          0 :                         continue;
     357                 :            :                     }
     358                 :            :                 }
     359         [ #  # ]:          0 :                 if( nCurrentColumn < nCurrentColumnCount )
     360 [ #  # ][ #  # ]:          0 :                     aColumnWidths[nCurrentColumn] = std::max( nNewWidth, aColumnWidths[nCurrentColumn] );
                 [ #  # ]
     361                 :            :                 else
     362         [ #  # ]:          0 :                     aColumnWidths.push_back(nNewWidth);
     363                 :            : 
     364                 :            :                 //do the columns still fit into the given size?
     365                 :          0 :                 nCurrentColumnCount = aColumnWidths.size();//update count
     366                 :          0 :                 sal_Int32 nSumWidth = 0;
     367         [ #  # ]:          0 :                 for( sal_Int32 nC=0; nC<nCurrentColumnCount; nC++ )
     368         [ #  # ]:          0 :                     nSumWidth += aColumnWidths[nC];
     369                 :            : 
     370 [ #  # ][ #  # ]:          0 :                 if( nSumWidth <= rAvailableSpace.Width || nCurrentColumnCount==1 )
     371                 :            :                 {
     372                 :            :                     //all good proceed with next entry
     373                 :          0 :                     continue;
     374                 :            :                 }
     375                 :            :                 else
     376                 :            :                 {
     377                 :            :                     //not enough space for the current amount of columns
     378                 :            :                     //try again with less columns
     379                 :          0 :                     nMaxColumnCount = nCurrentColumnCount-1;
     380                 :          0 :                     nN=-1;
     381                 :          0 :                     nCurrentRow=0;
     382                 :          0 :                     nCurrentColumn=-1;
     383                 :          0 :                     aColumnWidths.clear();
     384                 :          0 :                 }
     385                 :            :             }
     386                 :            :             else
     387                 :            :             {
     388                 :            :                 //add a new row and try the same entry again
     389                 :          0 :                 nCurrentRow++;
     390                 :          0 :                 nCurrentColumn=-1;
     391                 :          0 :                 nN--;
     392                 :            :             }
     393         [ #  # ]:          0 :         }
     394                 :          0 :         nNumberOfColumns = aColumnWidths.size();
     395                 :          0 :         nNumberOfRows = nCurrentRow+1;
     396                 :            : 
     397                 :            :         //check if there is not enough space so that some entries must be removed
     398 [ #  # ][ #  # ]:          0 :         lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes );
     399         [ #  # ]:          0 :         nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize );
     400                 :          0 :         sal_Int32 nSumHeight = 0;
     401         [ #  # ]:          0 :         for( sal_Int32 nR=0; nR<nNumberOfRows; nR++ )
     402         [ #  # ]:          0 :             nSumHeight += aRowHeights[nR];
     403                 :          0 :         sal_Int32 nRemainingSpace = rAvailableSpace.Height - nSumHeight;
     404                 :            : 
     405         [ #  # ]:          0 :         if( nRemainingSpace<0 )
     406                 :            :         {
     407                 :            :             //remove entries that are too big
     408         [ #  # ]:          0 :             for( sal_Int32 nR=nNumberOfRows; nR--; )
     409                 :            :             {
     410         [ #  # ]:          0 :                 for( sal_Int32 nC=nNumberOfColumns; nC--; )
     411                 :            :                 {
     412                 :          0 :                     sal_Int32 nEntry = (nC + nR * nNumberOfColumns);
     413         [ #  # ]:          0 :                     if( nEntry < static_cast<sal_Int32>(aTextShapes.size()) )
     414                 :            :                     {
     415         [ #  # ]:          0 :                         DrawModelWrapper::removeShape( aTextShapes[nEntry] );
     416         [ #  # ]:          0 :                         aTextShapes.pop_back();
     417                 :            :                     }
     418         [ #  # ]:          0 :                     if( nEntry < nNumberOfEntries )
     419                 :            :                     {
     420         [ #  # ]:          0 :                         DrawModelWrapper::removeShape( rEntries[ nEntry ].aSymbol );
     421         [ #  # ]:          0 :                         rEntries.pop_back();
     422                 :          0 :                         nNumberOfEntries--;
     423                 :            :                     }
     424                 :            :                 }
     425         [ #  # ]:          0 :                 nSumHeight -= aRowHeights[nR];
     426         [ #  # ]:          0 :                 aRowHeights.pop_back();
     427                 :          0 :                 nRemainingSpace = rAvailableSpace.Height - nSumHeight;
     428         [ #  # ]:          0 :                 if( nRemainingSpace>=0 )
     429                 :          0 :                     break;
     430                 :            :             }
     431                 :          0 :             nNumberOfRows = static_cast<sal_Int32>(aRowHeights.size());
     432                 :            :         }
     433         [ #  # ]:          0 :         if( nRemainingSpace > 0 )
     434                 :            :         {
     435                 :          0 :             sal_Int32 nNormalSpacingHeight = 2*nYPadding+(nNumberOfRows-1)*nYOffset;
     436         [ #  # ]:          0 :             if( nRemainingSpace < nNormalSpacingHeight )
     437                 :            :             {
     438                 :            :                 //reduce spacing between the entries
     439                 :          0 :                 nYPadding = nYOffset = nRemainingSpace/(nNumberOfRows+1);
     440                 :            :             }
     441                 :            :             else
     442                 :            :             {
     443                 :            :                 //we have some space left that should be spread equally between all rows
     444                 :          0 :                 sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingHeight)/(nNumberOfRows+1);
     445                 :          0 :                 nYPadding += nRemainingSingleSpace;
     446                 :          0 :                 nYOffset += nRemainingSingleSpace;
     447                 :            :             }
     448                 :            :         }
     449                 :            : 
     450                 :            :         //check spacing between columns
     451                 :          0 :         sal_Int32 nSumWidth = 0;
     452         [ #  # ]:          0 :         for( sal_Int32 nC=0; nC<nNumberOfColumns; nC++ )
     453         [ #  # ]:          0 :             nSumWidth += aColumnWidths[nC];
     454                 :          0 :         nRemainingSpace = rAvailableSpace.Width - nSumWidth;
     455         [ #  # ]:          0 :         if( nRemainingSpace>=0 )
     456                 :            :         {
     457                 :          0 :             sal_Int32 nNormalSpacingWidth = 2*nXPadding+(nNumberOfColumns-1)*nXOffset;
     458         [ #  # ]:          0 :             if( nRemainingSpace < nNormalSpacingWidth )
     459                 :            :             {
     460                 :            :                 //reduce spacing between the entries
     461                 :          0 :                 nXPadding = nXOffset = nRemainingSpace/(nNumberOfColumns+1);
     462                 :            :             }
     463                 :            :             else
     464                 :            :             {
     465                 :            :                 //we have some space left that should be spread equally between all columns
     466                 :          0 :                 sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingWidth)/(nNumberOfColumns+1);
     467                 :          0 :                 nXPadding += nRemainingSingleSpace;
     468                 :          0 :                 nXOffset += nRemainingSingleSpace;
     469                 :            :             }
     470                 :            :         }
     471                 :            :     }
     472         [ +  - ]:        956 :     else if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_HIGH )
     473                 :            :     {
     474                 :            :         sal_Int32 nMaxNumberOfRows = nMaxEntryHeight
     475                 :            :             ? (rAvailableSpace.Height - 2*nYPadding ) / nMaxEntryHeight
     476         [ +  - ]:        956 :             : 0;
     477                 :            : 
     478                 :            :         nNumberOfColumns = nMaxNumberOfRows
     479                 :            :             ? static_cast< sal_Int32 >(
     480                 :            :                 ceil( static_cast< double >( nNumberOfEntries ) /
     481                 :        956 :                       static_cast< double >( nMaxNumberOfRows ) ))
     482         [ +  - ]:        956 :             : 0;
     483                 :            :         nNumberOfRows =  nNumberOfColumns
     484                 :            :             ? static_cast< sal_Int32 >(
     485                 :            :                 ceil( static_cast< double >( nNumberOfEntries ) /
     486                 :        944 :                       static_cast< double >( nNumberOfColumns ) ))
     487         [ +  + ]:        956 :             : 0;
     488                 :            :     }
     489         [ #  # ]:          0 :     else if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_WIDE )
     490                 :            :     {
     491                 :            :         sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth
     492                 :            :             ? (rAvailableSpace.Width - 2*nXPadding ) / nMaxEntryWidth
     493         [ #  # ]:          0 :             : 0;
     494                 :            : 
     495                 :            :         nNumberOfRows = nMaxNumberOfColumns
     496                 :            :             ? static_cast< sal_Int32 >(
     497                 :            :                 ceil( static_cast< double >( nNumberOfEntries ) /
     498                 :          0 :                       static_cast< double >( nMaxNumberOfColumns ) ))
     499         [ #  # ]:          0 :             : 0;
     500                 :            :         nNumberOfColumns = nNumberOfRows
     501                 :            :             ? static_cast< sal_Int32 >(
     502                 :            :                 ceil( static_cast< double >( nNumberOfEntries ) /
     503                 :          0 :                       static_cast< double >( nNumberOfRows ) ))
     504         [ #  # ]:          0 :             : 0;
     505                 :            :     }
     506                 :            :     else // ::com::sun::star::chart::ChartLegendExpansion_BALANCED
     507                 :            :     {
     508                 :            :         double fAspect = nMaxEntryHeight
     509                 :            :             ? static_cast< double >( nMaxEntryWidth ) / static_cast< double >( nMaxEntryHeight )
     510         [ #  # ]:          0 :             : 0.0;
     511                 :            : 
     512                 :            :         nNumberOfRows = static_cast< sal_Int32 >(
     513                 :          0 :             ceil( sqrt( static_cast< double >( nNumberOfEntries ) * fAspect )));
     514                 :            :         nNumberOfColumns = nNumberOfRows
     515                 :            :             ? static_cast< sal_Int32 >(
     516                 :            :                 ceil( static_cast< double >( nNumberOfEntries ) /
     517                 :          0 :                       static_cast< double >( nNumberOfRows ) ))
     518         [ #  # ]:          0 :             : 0;
     519                 :            :     }
     520                 :            : 
     521         [ +  + ]:        956 :     if(nNumberOfRows<=0)
     522                 :            :         return aResultingLegendSize;
     523                 :            : 
     524         [ +  - ]:        944 :     if( eExpansion != ::com::sun::star::chart::ChartLegendExpansion_CUSTOM )
     525                 :            :     {
     526 [ +  - ][ +  - ]:        944 :         lcl_collectColumnWidths( aColumnWidths, nNumberOfRows, nNumberOfColumns, aTextShapes, nSymbolPlusDistanceWidth );
     527 [ +  - ][ +  - ]:        944 :         lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes );
     528         [ +  - ]:        944 :         nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize );
     529                 :            :     }
     530                 :            : 
     531                 :        944 :     sal_Int32 nCurrentXPos = nXPadding;
     532                 :        944 :     sal_Int32 nCurrentYPos = nYPadding;
     533         [ -  + ]:        944 :     if( !bSymbolsLeftSide )
     534                 :          0 :         nCurrentXPos = -nXPadding;
     535                 :            : 
     536                 :            :     // place entries into column and rows
     537                 :        944 :     sal_Int32 nMaxYPos = 0;
     538                 :        944 :     sal_Int32 nRow = 0;
     539                 :        944 :     sal_Int32 nColumn = 0;
     540         [ +  + ]:       1905 :     for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn )
     541                 :            :     {
     542                 :        961 :         nCurrentYPos = nYPadding;
     543         [ +  + ]:       4183 :         for( nRow = 0; nRow < nNumberOfRows; ++nRow )
     544                 :            :         {
     545                 :       3222 :             sal_Int32 nEntry = (nColumn + nRow * nNumberOfColumns);
     546         [ +  + ]:       3222 :             if( nEntry >= nNumberOfEntries )
     547                 :            :                 break;
     548                 :            : 
     549                 :            :             // text shape
     550                 :       3205 :             Reference< drawing::XShape > xTextShape( aTextShapes[nEntry] );
     551         [ +  - ]:       3205 :             if( xTextShape.is() )
     552                 :            :             {
     553 [ +  - ][ +  - ]:       3205 :                 awt::Size aTextSize( xTextShape->getSize() );
     554                 :       3205 :                 sal_Int32 nTextXPos = nCurrentXPos + nSymbolPlusDistanceWidth;
     555         [ -  + ]:       3205 :                 if( !bSymbolsLeftSide )
     556                 :          0 :                     nTextXPos = nCurrentXPos - nSymbolPlusDistanceWidth - aTextSize.Width;
     557 [ +  - ][ +  - ]:       3205 :                 xTextShape->setPosition( awt::Point( nTextXPos, nCurrentYPos ));
     558                 :            :             }
     559                 :            : 
     560                 :            :             // symbol
     561                 :       3205 :             Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol );
     562         [ +  - ]:       3205 :             if( xSymbol.is() )
     563                 :            :             {
     564                 :       3205 :                 awt::Size aSymbolSize( rMaxSymbolExtent );
     565                 :       3205 :                 sal_Int32 nSymbolXPos = nCurrentXPos;
     566         [ -  + ]:       3205 :                 if( !bSymbolsLeftSide )
     567                 :          0 :                     nSymbolXPos = nCurrentXPos - rMaxSymbolExtent.Width;
     568                 :       3205 :                 sal_Int32 nSymbolYPos = nCurrentYPos + ( ( nTextLineHeight - aSymbolSize.Height ) / 2 );
     569 [ +  - ][ +  - ]:       3205 :                 xSymbol->setPosition( awt::Point( nSymbolXPos, nSymbolYPos ) );
     570                 :            :             }
     571                 :            : 
     572         [ +  - ]:       3205 :             nCurrentYPos += aRowHeights[ nRow ];
     573         [ +  + ]:       3205 :             if( nRow+1 < nNumberOfRows )
     574                 :       2261 :                 nCurrentYPos += nYOffset;
     575         [ +  - ]:       3205 :             nMaxYPos = ::std::max( nMaxYPos, nCurrentYPos );
     576                 :       3205 :         }
     577         [ +  - ]:        961 :         if( bSymbolsLeftSide )
     578                 :            :         {
     579         [ +  - ]:        961 :             nCurrentXPos += aColumnWidths[nColumn];
     580         [ +  + ]:        961 :             if( nColumn+1 < nNumberOfColumns )
     581                 :         17 :                 nCurrentXPos += nXOffset;
     582                 :            :         }
     583                 :            :         else
     584                 :            :         {
     585         [ #  # ]:          0 :             nCurrentXPos -= aColumnWidths[nColumn];
     586         [ #  # ]:          0 :             if( nColumn+1 < nNumberOfColumns )
     587                 :          0 :                 nCurrentXPos -= nXOffset;
     588                 :            :         }
     589                 :            :     }
     590                 :            : 
     591         [ +  - ]:        944 :     if( !bIsCustomSize )
     592                 :            :     {
     593         [ +  - ]:        944 :         if( bSymbolsLeftSide )
     594                 :        944 :             aResultingLegendSize.Width  = nCurrentXPos + nXPadding;
     595                 :            :         else
     596                 :            :         {
     597                 :          0 :             sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding);
     598                 :          0 :             aResultingLegendSize.Width  = nLegendWidth;
     599                 :            :         }
     600                 :        944 :         aResultingLegendSize.Height = nMaxYPos + nYPadding;
     601                 :            :     }
     602                 :            : 
     603         [ -  + ]:        944 :     if( !bSymbolsLeftSide )
     604                 :            :     {
     605                 :          0 :         sal_Int32 nLegendWidth = aResultingLegendSize.Width;
     606                 :          0 :         awt::Point aPos(0,0);
     607         [ #  # ]:          0 :         for( sal_Int32 nEntry=0; nEntry<nNumberOfEntries; nEntry++ )
     608                 :            :         {
     609                 :          0 :             Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol );
     610 [ #  # ][ #  # ]:          0 :             aPos = xSymbol->getPosition();
     611                 :          0 :             aPos.X += nLegendWidth;
     612 [ #  # ][ #  # ]:          0 :             xSymbol->setPosition( aPos );
     613                 :          0 :             Reference< drawing::XShape > xText( aTextShapes[ nEntry ] );
     614 [ #  # ][ #  # ]:          0 :             aPos = xText->getPosition();
     615                 :          0 :             aPos.X += nLegendWidth;
     616 [ #  # ][ #  # ]:          0 :             xText->setPosition( aPos );
     617                 :          0 :         }
     618                 :            :     }
     619                 :            : 
     620                 :        956 :     return aResultingLegendSize;
     621                 :            : }
     622                 :            : 
     623                 :            : // #i109336# Improve auto positioning in chart
     624                 :       2236 : sal_Int32 lcl_getLegendLeftRightMargin()
     625                 :            : {
     626                 :       2236 :     return 210;  // 1/100 mm
     627                 :            : }
     628                 :            : 
     629                 :            : // #i109336# Improve auto positioning in chart
     630                 :       1283 : sal_Int32 lcl_getLegendTopBottomMargin()
     631                 :            : {
     632                 :       1283 :     return 185;  // 1/100 mm
     633                 :            : }
     634                 :            : 
     635                 :        953 : chart2::RelativePosition lcl_getDefaultPosition( LegendPosition ePos, const awt::Rectangle& rOutAvailableSpace, const awt::Size & rPageSize )
     636                 :            : {
     637                 :        953 :     chart2::RelativePosition aResult;
     638                 :            : 
     639   [ -  +  -  -  :        953 :     switch( ePos )
                   -  - ]
     640                 :            :     {
     641                 :            :         case LegendPosition_LINE_START:
     642                 :            :             {
     643                 :            :                 // #i109336# Improve auto positioning in chart
     644                 :          0 :                 const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) /
     645                 :          0 :                     static_cast< double >( rPageSize.Width ) );
     646                 :            :                 aResult = chart2::RelativePosition(
     647                 :          0 :                     fDefaultDistance, 0.5, drawing::Alignment_LEFT );
     648                 :            :             }
     649                 :          0 :             break;
     650                 :            :         case LegendPosition_LINE_END:
     651                 :            :             {
     652                 :            :                 // #i109336# Improve auto positioning in chart
     653                 :        953 :                 const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) /
     654                 :        953 :                     static_cast< double >( rPageSize.Width ) );
     655                 :            :                 aResult = chart2::RelativePosition(
     656                 :        953 :                     1.0 - fDefaultDistance, 0.5, drawing::Alignment_RIGHT );
     657                 :            :             }
     658                 :        953 :             break;
     659                 :            :         case LegendPosition_PAGE_START:
     660                 :            :             {
     661                 :            :                 // #i109336# Improve auto positioning in chart
     662                 :          0 :                 const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) /
     663                 :          0 :                     static_cast< double >( rPageSize.Height ) );
     664                 :          0 :                 double fDistance = (static_cast<double>(rOutAvailableSpace.Y)/static_cast<double>(rPageSize.Height)) + fDefaultDistance;
     665                 :            :                 aResult = chart2::RelativePosition(
     666                 :          0 :                     0.5, fDistance, drawing::Alignment_TOP );
     667                 :            :             }
     668                 :          0 :             break;
     669                 :            :         case LegendPosition_PAGE_END:
     670                 :            :             {
     671                 :            :                 // #i109336# Improve auto positioning in chart
     672                 :          0 :                 const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) /
     673                 :          0 :                     static_cast< double >( rPageSize.Height ) );
     674                 :            :                 aResult = chart2::RelativePosition(
     675                 :          0 :                     0.5, 1.0 - fDefaultDistance, drawing::Alignment_BOTTOM );
     676                 :            :             }
     677                 :          0 :             break;
     678                 :            : 
     679                 :            :         case LegendPosition_CUSTOM:
     680                 :            :             // to avoid warning
     681                 :            :         case LegendPosition_MAKE_FIXED_SIZE:
     682                 :            :             // nothing to be set
     683                 :          0 :             break;
     684                 :            :     }
     685                 :            : 
     686                 :        953 :     return aResult;
     687                 :            : }
     688                 :            : 
     689                 :            : /**  @return
     690                 :            :          a point relative to the upper left corner that can be used for
     691                 :            :          XShape::setPosition()
     692                 :            : */
     693                 :       1283 : awt::Point lcl_calculatePositionAndRemainingSpace(
     694                 :            :     awt::Rectangle & rRemainingSpace,
     695                 :            :     const awt::Size & rPageSize,
     696                 :            :     chart2::RelativePosition aRelPos,
     697                 :            :     LegendPosition ePos,
     698                 :            :     const awt::Size& aLegendSize )
     699                 :            : {
     700                 :            :     // calculate position
     701                 :            :     awt::Point aResult(
     702                 :            :         static_cast< sal_Int32 >( aRelPos.Primary * rPageSize.Width ),
     703                 :       1283 :         static_cast< sal_Int32 >( aRelPos.Secondary * rPageSize.Height ));
     704                 :            : 
     705                 :            :     aResult = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
     706                 :       1283 :         aResult, aLegendSize, aRelPos.Anchor );
     707                 :            : 
     708                 :            :     // adapt rRemainingSpace if LegendPosition is not CUSTOM
     709                 :            :     // #i109336# Improve auto positioning in chart
     710                 :       1283 :     sal_Int32 nXDistance = lcl_getLegendLeftRightMargin();
     711                 :       1283 :     sal_Int32 nYDistance = lcl_getLegendTopBottomMargin();
     712   [ -  +  -  -  :       1283 :     switch( ePos )
                      + ]
     713                 :            :     {
     714                 :            :         case LegendPosition_LINE_START:
     715                 :            :             {
     716                 :          0 :                 sal_Int32 nExtent = aLegendSize.Width;
     717                 :          0 :                 rRemainingSpace.Width -= ( nExtent + nXDistance );
     718                 :          0 :                 rRemainingSpace.X += ( nExtent + nXDistance );
     719                 :            :             }
     720                 :          0 :         break;
     721                 :            :         case LegendPosition_LINE_END:
     722                 :            :             {
     723                 :       1280 :                 rRemainingSpace.Width -= ( aLegendSize.Width + nXDistance );
     724                 :            :             }
     725                 :       1280 :             break;
     726                 :            :         case LegendPosition_PAGE_START:
     727                 :            :             {
     728                 :          0 :                 sal_Int32 nExtent = aLegendSize.Height;
     729                 :          0 :                 rRemainingSpace.Height -= ( nExtent + nYDistance );
     730                 :          0 :                 rRemainingSpace.Y += ( nExtent + nYDistance );
     731                 :            :             }
     732                 :          0 :         break;
     733                 :            :         case LegendPosition_PAGE_END:
     734                 :            :             {
     735                 :          0 :                 rRemainingSpace.Height -= ( aLegendSize.Height + nYDistance );
     736                 :            :             }
     737                 :          0 :             break;
     738                 :            : 
     739                 :            :         default:
     740                 :            :             // nothing
     741                 :          3 :             break;
     742                 :            :     }
     743                 :            : 
     744                 :            :     // adjust the legend position. Esp. for old files that had slightly smaller legends
     745                 :       1283 :     const sal_Int32 nEdgeDistance( 30 );
     746         [ -  + ]:       1283 :     if( aResult.X + aLegendSize.Width > rPageSize.Width )
     747                 :            :     {
     748                 :          0 :         sal_Int32 nNewX( (rPageSize.Width - aLegendSize.Width) - nEdgeDistance );
     749         [ #  # ]:          0 :         if( nNewX > rPageSize.Width / 4 )
     750                 :          0 :             aResult.X = nNewX;
     751                 :            :     }
     752         [ -  + ]:       1283 :     if( aResult.Y + aLegendSize.Height > rPageSize.Height )
     753                 :            :     {
     754                 :          0 :         sal_Int32 nNewY( (rPageSize.Height - aLegendSize.Height) - nEdgeDistance );
     755         [ #  # ]:          0 :         if( nNewY > rPageSize.Height / 4 )
     756                 :          0 :             aResult.Y = nNewY;
     757                 :            :     }
     758                 :            : 
     759                 :       1283 :     return aResult;
     760                 :            : }
     761                 :            : 
     762                 :        956 : bool lcl_shouldSymbolsBePlacedOnTheLeftSide( const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode )
     763                 :            : {
     764                 :        956 :     bool bSymbolsLeftSide = true;
     765                 :            :     try
     766                 :            :     {
     767 [ +  - ][ +  - ]:        956 :         if( SvtLanguageOptions().IsCTLFontEnabled() )
         [ +  - ][ +  + ]
     768                 :            :         {
     769         [ +  - ]:          3 :             if(xLegendProp.is())
     770                 :            :             {
     771                 :          3 :                 sal_Int16 nWritingMode=-1;
     772 [ +  - ][ +  - ]:          3 :                 if( (xLegendProp->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode) )
                 [ +  - ]
           [ +  -  #  # ]
     773                 :            :                 {
     774         [ +  - ]:          3 :                     if( nWritingMode == text::WritingMode2::PAGE )
     775                 :          3 :                         nWritingMode = nDefaultWritingMode;
     776         [ -  + ]:          3 :                     if( nWritingMode == text::WritingMode2::RL_TB )
     777                 :          3 :                         bSymbolsLeftSide=false;
     778                 :            :                 }
     779                 :            :             }
     780                 :            :         }
     781                 :            :     }
     782                 :          0 :     catch( const uno::Exception & ex )
     783                 :            :     {
     784                 :            :         ASSERT_EXCEPTION( ex );
     785                 :            :     }
     786                 :        956 :     return bSymbolsLeftSide;
     787                 :            : }
     788                 :            : 
     789                 :            : } // anonymous namespace
     790                 :            : 
     791                 :        956 : VLegend::VLegend(
     792                 :            :     const Reference< XLegend > & xLegend,
     793                 :            :     const Reference< uno::XComponentContext > & xContext,
     794                 :            :     const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ) :
     795                 :            :         m_xLegend( xLegend ),
     796                 :            :         m_xContext( xContext ),
     797         [ +  - ]:        956 :         m_aLegendEntryProviderList( rLegendEntryProviderList )
     798                 :            : {
     799                 :        956 : }
     800                 :            : 
     801                 :            : // ----------------------------------------
     802                 :            : 
     803                 :        956 : void VLegend::init(
     804                 :            :     const Reference< drawing::XShapes >& xTargetPage,
     805                 :            :     const Reference< lang::XMultiServiceFactory >& xFactory,
     806                 :            :     const Reference< frame::XModel >& xModel )
     807                 :            : {
     808                 :        956 :     m_xTarget = xTargetPage;
     809                 :        956 :     m_xShapeFactory = xFactory;
     810                 :        956 :     m_xModel = xModel;
     811                 :        956 : }
     812                 :            : 
     813                 :            : // ----------------------------------------
     814                 :            : 
     815                 :        956 : void VLegend::setDefaultWritingMode( sal_Int16 nDefaultWritingMode )
     816                 :            : {
     817                 :        956 :     m_nDefaultWritingMode = nDefaultWritingMode;
     818                 :        956 : }
     819                 :            : 
     820                 :            : // ----------------------------------------
     821                 :            : 
     822                 :       1003 : bool VLegend::isVisible( const Reference< XLegend > & xLegend )
     823                 :            : {
     824         [ +  + ]:       1003 :     if( ! xLegend.is())
     825                 :         10 :         return sal_False;
     826                 :            : 
     827                 :        993 :     sal_Bool bShow = sal_False;
     828                 :            :     try
     829                 :            :     {
     830         [ +  - ]:        993 :         Reference< beans::XPropertySet > xLegendProp( xLegend, uno::UNO_QUERY_THROW );
     831 [ +  - ][ +  - ]:        993 :         xLegendProp->getPropertyValue( C2U( "Show" )) >>= bShow;
         [ +  - ][ #  # ]
     832                 :            :     }
     833         [ #  # ]:          0 :     catch( const uno::Exception & ex )
     834                 :            :     {
     835                 :            :         ASSERT_EXCEPTION( ex );
     836                 :            :     }
     837                 :            : 
     838                 :       1003 :     return bShow;
     839                 :            : }
     840                 :            : 
     841                 :            : // ----------------------------------------
     842                 :            : 
     843                 :        956 : void VLegend::createShapes(
     844                 :            :     const awt::Size & rAvailableSpace,
     845                 :            :     const awt::Size & rPageSize )
     846                 :            : {
     847         [ -  + ]:       1912 :     if(! (m_xLegend.is() &&
     848                 :        956 :           m_xShapeFactory.is() &&
     849         [ -  + ]:       1912 :           m_xTarget.is()))
           [ +  -  +  - ]
     850                 :        956 :         return;
     851                 :            : 
     852                 :            :     try
     853                 :            :     {
     854                 :            :         //create shape and add to page
     855         [ +  - ]:        956 :         m_xShape.set( m_xShapeFactory->createInstance(
     856 [ +  - ][ +  - ]:        956 :                           C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY );
                 [ +  - ]
     857 [ +  - ][ +  - ]:        956 :         m_xTarget->add( m_xShape );
     858                 :            : 
     859                 :            :         // set name to enable selection
     860                 :            :         {
     861         [ +  - ]:        956 :             OUString aLegendParticle( ObjectIdentifier::createParticleForLegend( m_xLegend, m_xModel ) );
     862 [ +  - ][ +  - ]:        956 :             ShapeFactory::setShapeName( m_xShape, ObjectIdentifier::createClassifiedIdentifierForParticle( aLegendParticle ) );
     863                 :            :         }
     864                 :            : 
     865                 :            :         // create and insert sub-shapes
     866         [ +  - ]:        956 :         Reference< drawing::XShapes > xLegendContainer( m_xShape, uno::UNO_QUERY );
     867         [ +  - ]:        956 :         if( xLegendContainer.is())
     868                 :            :         {
     869                 :            :             Reference< drawing::XShape > xBorder(
     870         [ +  - ]:        956 :                 m_xShapeFactory->createInstance(
     871 [ +  - ][ +  - ]:        956 :                     C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY );
                 [ +  - ]
     872                 :            : 
     873                 :            :             // for quickly setting properties
     874         [ +  - ]:        956 :             tPropertyValues aLineFillProperties;
     875         [ +  - ]:        956 :             tPropertyValues aTextProperties;
     876                 :            : 
     877         [ +  - ]:        956 :             Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY );
     878                 :        956 :             ::com::sun::star::chart::ChartLegendExpansion eExpansion = ::com::sun::star::chart::ChartLegendExpansion_HIGH;
     879                 :        956 :             awt::Size aLegendSize( rAvailableSpace );
     880                 :            : 
     881         [ +  - ]:        956 :             if( xLegendProp.is())
     882                 :            :             {
     883                 :            :                 // get Expansion property
     884 [ +  - ][ +  - ]:        956 :                 xLegendProp->getPropertyValue( C2U( "Expansion" )) >>= eExpansion;
         [ +  - ][ +  - ]
     885         [ -  + ]:        956 :                 if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_CUSTOM )
     886                 :            :                 {
     887                 :          0 :                     RelativeSize aRelativeSize;
     888 [ #  # ][ #  # ]:          0 :                     if ((xLegendProp->getPropertyValue( C2U( "RelativeSize" )) >>= aRelativeSize))
         [ #  # ][ #  # ]
                 [ #  # ]
     889                 :            :                     {
     890                 :          0 :                         aLegendSize.Width = static_cast<sal_Int32>(::rtl::math::approxCeil( aRelativeSize.Primary * rPageSize.Width ));
     891                 :          0 :                         aLegendSize.Height = static_cast<sal_Int32>(::rtl::math::approxCeil( aRelativeSize.Secondary * rPageSize.Height ));
     892                 :            :                     }
     893                 :            :                     else
     894                 :          0 :                         eExpansion = ::com::sun::star::chart::ChartLegendExpansion_HIGH;
     895                 :            :                 }
     896         [ +  - ]:        956 :                 lcl_getProperties( xLegendProp, aLineFillProperties, aTextProperties, rPageSize );
     897                 :            :             }
     898                 :            : 
     899         [ +  - ]:        956 :             if( xBorder.is())
     900                 :            :             {
     901 [ +  - ][ +  - ]:        956 :                 xLegendContainer->add( xBorder );
     902                 :            : 
     903                 :            :                 // apply legend properties
     904                 :            :                 PropertyMapper::setMultiProperties(
     905                 :            :                     aLineFillProperties.first, aLineFillProperties.second,
     906 [ +  - ][ +  - ]:        956 :                     Reference< beans::XPropertySet >( xBorder, uno::UNO_QUERY ));
     907                 :            : 
     908                 :            :                 //because of this name this border will be used for marking the legend
     909 [ +  - ][ +  - ]:        956 :                 ShapeFactory(m_xShapeFactory).setShapeName( xBorder, C2U("MarkHandles") );
         [ +  - ][ +  - ]
     910                 :            :             }
     911                 :            : 
     912                 :            :             // create entries
     913         [ +  - ]:        956 :             double fViewFontSize = lcl_CalcViewFontSize( xLegendProp, rPageSize );//todo
     914                 :            :             // #i109336# Improve auto positioning in chart
     915                 :        956 :             sal_Int32 nSymbolHeigth = static_cast< sal_Int32 >( fViewFontSize * 0.6  );
     916                 :        956 :             sal_Int32 nSymbolWidth = static_cast< sal_Int32 >( nSymbolHeigth );
     917                 :            : 
     918         [ +  - ]:        956 :             ::std::vector< LegendEntryProvider* >::const_iterator       aIter = m_aLegendEntryProviderList.begin();
     919         [ +  - ]:        956 :             const ::std::vector< LegendEntryProvider* >::const_iterator aEnd  = m_aLegendEntryProviderList.end();
     920 [ +  - ][ +  - ]:       1900 :             for( aIter = m_aLegendEntryProviderList.begin(); aIter != aEnd; ++aIter )
                 [ +  + ]
     921                 :            :             {
     922                 :        944 :                 LegendEntryProvider* pLegendEntryProvider( *aIter );
     923         [ +  - ]:        944 :                 if( pLegendEntryProvider )
     924                 :            :                 {
     925         [ +  - ]:        944 :                     awt::Size aCurrentRatio = pLegendEntryProvider->getPreferredLegendKeyAspectRatio();
     926                 :        944 :                     sal_Int32 nCurrentWidth = aCurrentRatio.Width;
     927         [ +  + ]:        944 :                     if( aCurrentRatio.Height > 0 )
     928                 :            :                     {
     929                 :        879 :                         nCurrentWidth = nSymbolHeigth* aCurrentRatio.Width/aCurrentRatio.Height;
     930                 :            :                     }
     931         [ +  - ]:        944 :                     nSymbolWidth = std::max( nSymbolWidth, nCurrentWidth );
     932                 :            :                 }
     933                 :            :             }
     934                 :        956 :             awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeigth );
     935                 :            : 
     936         [ +  - ]:        956 :             tViewLegendEntryContainer aViewEntries;
     937 [ +  - ][ +  - ]:       1900 :             for( aIter = m_aLegendEntryProviderList.begin(); aIter != aEnd; ++aIter )
                 [ +  + ]
     938                 :            :             {
     939                 :        944 :                 LegendEntryProvider* pLegendEntryProvider( *aIter );
     940         [ +  - ]:        944 :                 if( pLegendEntryProvider )
     941                 :            :                 {
     942         [ +  - ]:        944 :                     std::vector< ViewLegendEntry > aNewEntries = pLegendEntryProvider->createLegendEntries( aMaxSymbolExtent, eExpansion, xLegendProp, xLegendContainer, m_xShapeFactory, m_xContext );
     943         [ +  - ]:        944 :                     aViewEntries.insert( aViewEntries.end(), aNewEntries.begin(), aNewEntries.end() );
     944                 :            :                 }
     945                 :            :             }
     946                 :            : 
     947         [ +  - ]:        956 :             bool bSymbolsLeftSide = lcl_shouldSymbolsBePlacedOnTheLeftSide( xLegendProp, m_nDefaultWritingMode );
     948                 :            : 
     949                 :            :             // place entries
     950                 :            :             aLegendSize = lcl_placeLegendEntries( aViewEntries, eExpansion, bSymbolsLeftSide, fViewFontSize, aMaxSymbolExtent
     951         [ +  - ]:        956 :                 , aTextProperties, xLegendContainer, m_xShapeFactory, aLegendSize );
     952                 :            : 
     953         [ +  - ]:        956 :             if( xBorder.is() )
     954 [ +  - ][ +  - ]:        956 :                 xBorder->setSize( aLegendSize );
         [ +  - ][ +  - ]
     955         [ #  # ]:        956 :         }
     956                 :            :     }
     957                 :          0 :     catch( const uno::Exception & ex )
     958                 :            :     {
     959                 :            :         ASSERT_EXCEPTION( ex );
     960                 :            :     }
     961                 :            : }
     962                 :            : 
     963                 :            : // ----------------------------------------
     964                 :            : 
     965                 :        956 : void VLegend::changePosition(
     966                 :            :     awt::Rectangle & rOutAvailableSpace,
     967                 :            :     const awt::Size & rPageSize )
     968                 :            : {
     969         [ -  + ]:        956 :     if(! m_xShape.is())
     970                 :        956 :         return;
     971                 :            : 
     972                 :            :     try
     973                 :            :     {
     974                 :            :         // determine position and alignment depending on default position
     975 [ +  - ][ +  - ]:        956 :         awt::Size aLegendSize = m_xShape->getSize();
     976         [ +  - ]:        956 :         Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY_THROW );
     977                 :        956 :         chart2::RelativePosition aRelativePosition;
     978                 :            : 
     979                 :            :         bool bAutoPosition =
     980 [ +  - ][ +  - ]:        956 :             ! (xLegendProp->getPropertyValue( C2U( "RelativePosition" )) >>= aRelativePosition);
         [ +  - ][ +  - ]
     981                 :            : 
     982                 :        956 :         LegendPosition ePos = LegendPosition_CUSTOM;
     983 [ +  - ][ +  - ]:        956 :         xLegendProp->getPropertyValue( C2U( "AnchorPosition" )) >>= ePos;
         [ +  - ][ +  - ]
     984                 :            : 
     985                 :            :         //calculate position
     986         [ +  + ]:        956 :         if( bAutoPosition )
     987                 :            :         {
     988                 :            :             // auto position: relative to remaining space
     989                 :        626 :             aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize );
     990                 :            :             awt::Point aPos = lcl_calculatePositionAndRemainingSpace(
     991         [ +  - ]:        626 :                 rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize );
     992 [ +  - ][ +  - ]:        626 :             m_xShape->setPosition( aPos );
     993                 :            :         }
     994                 :            :         else
     995                 :            :         {
     996                 :            :             // manual position: relative to whole page
     997                 :        330 :             awt::Rectangle aAvailableSpace( 0, 0, rPageSize.Width, rPageSize.Height );
     998                 :            :             awt::Point aPos = lcl_calculatePositionAndRemainingSpace(
     999         [ +  - ]:        330 :                 aAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize );
    1000 [ +  - ][ +  - ]:        330 :             m_xShape->setPosition( aPos );
    1001                 :            : 
    1002         [ +  + ]:        330 :             if( ePos != LegendPosition_CUSTOM )
    1003                 :            :             {
    1004                 :            :                 // calculate remaining space as if having autoposition:
    1005                 :        327 :                 aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize );
    1006                 :            :                 lcl_calculatePositionAndRemainingSpace(
    1007         [ +  - ]:        330 :                     rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize );
    1008                 :            :             }
    1009         [ #  # ]:        956 :         }
    1010                 :            :     }
    1011                 :          0 :     catch( const uno::Exception & ex )
    1012                 :            :     {
    1013                 :            :         ASSERT_EXCEPTION( ex );
    1014                 :            :     }
    1015                 :            : }
    1016                 :            : 
    1017                 :            : //.............................................................................
    1018                 :            : } //namespace chart
    1019                 :            : //.............................................................................
    1020                 :            : 
    1021                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10