diff options
Diffstat (limited to 'chart2/source/view/main/VLegend.cxx')
-rw-r--r-- | chart2/source/view/main/VLegend.cxx | 834 |
1 files changed, 834 insertions, 0 deletions
diff --git a/chart2/source/view/main/VLegend.cxx b/chart2/source/view/main/VLegend.cxx new file mode 100644 index 000000000000..7101a984ee24 --- /dev/null +++ b/chart2/source/view/main/VLegend.cxx @@ -0,0 +1,834 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "VLegend.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "CommonConverters.hxx" +#include "ObjectIdentifier.hxx" +#include "RelativePositionHelper.hxx" +#include "ShapeFactory.hxx" +#include "RelativeSizeHelper.hxx" +#include "LegendEntryProvider.hxx" +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> +#include <com/sun/star/chart2/LegendExpansion.hpp> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <rtl/ustrbuf.hxx> +#include <svl/languageoptions.hxx> + +#include <vector> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + +//............................................................................. +namespace chart +{ +//............................................................................. + +namespace +{ + +typedef ::std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues; + +typedef ::std::vector< ViewLegendEntry > tViewLegendEntryContainer; + +double lcl_CalcViewFontSize( + const Reference< beans::XPropertySet > & xProp, + const awt::Size & rReferenceSize ) +{ + double fResult = 10.0; + + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( xProp.is() && ( xProp->getPropertyValue( C2U( "CharHeight" )) >>= fFontHeight )) + { + fResult = fFontHeight; + try + { + if( (xProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) && + (aPropRefSize.Height > 0)) + { + // todo: find out if asian text is really used +// Reference< beans::XPropertySetInfo >xInfo( xProp, uno::UNO_QUERY ); +// float fFontHeight2 = fFontHeight; +// if( xInfo.is() && +// xInfo->hasPropertyByName(C2U("CharHeightAsian")) && +// (xProp->getPropertyValue(C2U("CharHeightAsian")) >>= fFontHeight2) && +// fFontHeight2 > fFontHeight ) +// { +// fFontHeight = fFontHeight2; +// } + +// if( xInfo.is() && +// xInfo->hasPropertyByName(C2U("CharHeightComplex")) && +// (xProp->getPropertyValue(C2U("CharHeightComplex")) >>= fFontHeight2) && +// fFontHeight2 > fFontHeight ) +// { +// fFontHeight = fFontHeight2; +// } + + fResult = ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ); + } + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + // pt -> 1/100th mm + return (fResult * (2540.0 / 72.0)); +} + +void lcl_getProperties( + const Reference< beans::XPropertySet > & xLegendProp, + tPropertyValues & rOutLineFillProperties, + tPropertyValues & rOutTextProperties, + sal_Int32 nMaxLabelWidth, + const awt::Size & rReferenceSize ) +{ + // Get Line- and FillProperties from model legend + if( xLegendProp.is()) + { + // set rOutLineFillProperties + ::chart::tPropertyNameValueMap aLineFillValueMap; + ::chart::PropertyMapper::getValueMap( aLineFillValueMap, ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xLegendProp ); + + aLineFillValueMap[ C2U("LineJoint") ] = uno::makeAny( drawing::LineJoint_ROUND ); + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap ); + + // set rOutTextProperties + ::chart::tPropertyNameValueMap aTextValueMap; + ::chart::PropertyMapper::getValueMap( aTextValueMap, ::chart::PropertyMapper::getPropertyNameMapForCharacterProperties(), xLegendProp ); + + drawing::TextHorizontalAdjust eHorizAdjust( drawing::TextHorizontalAdjust_LEFT ); + aTextValueMap[ C2U("TextAutoGrowHeight") ] = uno::makeAny( sal_True ); + aTextValueMap[ C2U("TextAutoGrowWidth") ] = uno::makeAny( sal_True ); + aTextValueMap[ C2U("TextHorizontalAdjust") ] = uno::makeAny( eHorizAdjust ); + aTextValueMap[ C2U("TextMaximumFrameWidth") ] = uno::makeAny( nMaxLabelWidth ); + + // recalculate font size + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( (xLegendProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) && + (aPropRefSize.Height > 0) && + (aTextValueMap[ C2U("CharHeight") ] >>= fFontHeight) ) + { + aTextValueMap[ C2U("CharHeight") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + + if( aTextValueMap[ C2U("CharHeightAsian") ] >>= fFontHeight ) + { + aTextValueMap[ C2U("CharHeightAsian") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + } + if( aTextValueMap[ C2U("CharHeightComplex") ] >>= fFontHeight ) + { + aTextValueMap[ C2U("CharHeightComplex") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + } + } + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutTextProperties.first, rOutTextProperties.second, aTextValueMap ); + } +} + +awt::Size lcl_createTextShapes( + const tViewLegendEntryContainer & rEntries, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< drawing::XShapes > & xTarget, + ::std::vector< Reference< drawing::XShape > > & rOutTextShapes, + const tPropertyValues & rTextProperties ) +{ + awt::Size aResult; + + for( tViewLegendEntryContainer::const_iterator aIt( rEntries.begin()); + aIt != rEntries.end(); ++aIt ) + { + try + { + // create label shape + Reference< drawing::XShape > xGroupShapeForSingleEntry( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY_THROW ); + Reference< drawing::XShape >xEntry( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.TextShape" )), uno::UNO_QUERY_THROW ); + xTarget->add( xGroupShapeForSingleEntry ); + + Reference< drawing::XShapes > xGroup( xGroupShapeForSingleEntry, uno::UNO_QUERY_THROW ); + xGroup->add( xEntry ); + + // set label text + Sequence< Reference< XFormattedString > > aLabelSeq = (*aIt).aLabel; + for( sal_Int32 i = 0; i < aLabelSeq.getLength(); ++i ) + { + // todo: support more than one text range + if( i == 1 ) + break; + + Reference< text::XTextRange > xRange( xEntry, uno::UNO_QUERY ); + OUString aLabelString( aLabelSeq[i]->getString()); + // workaround for Issue #i67540# + if( !aLabelString.getLength()) + aLabelString = C2U(" "); + if( xRange.is()) + xRange->setString( aLabelString ); + + PropertyMapper::setMultiProperties( + rTextProperties.first, rTextProperties.second, + Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY )); + + // adapt max-extent + awt::Size aCurrSize( xEntry->getSize()); + aResult.Width = ::std::max( aResult.Width, aCurrSize.Width ); + aResult.Height = ::std::max( aResult.Height, aCurrSize.Height ); + } + + rOutTextShapes.push_back( xGroupShapeForSingleEntry ); + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + return aResult; +} + + +void lcl_placeLegendEntries( + const tViewLegendEntryContainer & rEntries, + LegendExpansion eExpansion, + bool bSymbolsLeftSide, + const Reference< beans::XPropertySet > & xProperties, + tPropertyValues & rTextProperties, + const Reference< drawing::XShapes > & xTarget, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< uno::XComponentContext > & /* xContext */, + const awt::Size & rAvailableSpace, + const awt::Size & rPageSize, + awt::Size & rOutLegendSize ) +{ + double fViewFontSize = lcl_CalcViewFontSize( xProperties, rPageSize ); + + // padding as percentage of the font height + // #i109336# Improve auto positioning in chart + double fXPadding = 0.1; + double fYPadding = 0.2; + double fXOffset = 0.15; + double fYOffset = 0.15; + + const sal_Int32 nXPadding = static_cast< sal_Int32 >( fViewFontSize * fXPadding ); + const sal_Int32 nYPadding = static_cast< sal_Int32 >( fViewFontSize * fYPadding ); + const sal_Int32 nXOffset = static_cast< sal_Int32 >( fViewFontSize * fXOffset ); + const sal_Int32 nYOffset = static_cast< sal_Int32 >( fViewFontSize * fYOffset ); + + ::std::vector< Reference< drawing::XShape > > aTextShapes; + awt::Size aMaxEntryExtent = lcl_createTextShapes( + rEntries, xShapeFactory, xTarget, aTextShapes, rTextProperties ); + OSL_ASSERT( aTextShapes.size() == rEntries.size()); + + // #i109336# Improve auto positioning in chart + double fSymbolSizeFraction = 0.8; + awt::Size aMaxSymbolExtent( static_cast< sal_Int32 >( fViewFontSize * fSymbolSizeFraction * 3.0 / 2.0 ), + static_cast< sal_Int32 >( fViewFontSize * fSymbolSizeFraction ) ); + + sal_Int32 nCurrentXPos = nXPadding; + sal_Int32 nCurrentYPos = nYPadding; + sal_Int32 nMaxEntryWidth = 2 * nXOffset + aMaxSymbolExtent.Width + aMaxEntryExtent.Width; + sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height; + sal_Int32 nNumberOfEntries = rEntries.size(); + + if( !bSymbolsLeftSide ) + nCurrentXPos = -nXPadding; + + sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0; + + // determine layout depending on LegendExpansion + if( eExpansion == LegendExpansion_HIGH ) + { + sal_Int32 nMaxNumberOfRows = nMaxEntryHeight + ? (rAvailableSpace.Height - 2*nYPadding ) / nMaxEntryHeight + : 0; + + nNumberOfColumns = nMaxNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nMaxNumberOfRows ) )) + : 0; + nNumberOfRows = nNumberOfColumns + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfColumns ) )) + : 0; + } + else if( eExpansion == LegendExpansion_WIDE ) + { + sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth + ? (rAvailableSpace.Width - 2*nXPadding ) / nMaxEntryWidth + : 0; + + nNumberOfRows = nMaxNumberOfColumns + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nMaxNumberOfColumns ) )) + : 0; + nNumberOfColumns = nNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfRows ) )) + : 0; + } + else // LegendExpansion_BALANCED + { + double fAspect = nMaxEntryHeight + ? static_cast< double >( nMaxEntryWidth ) / static_cast< double >( nMaxEntryHeight ) + : 0.0; + + nNumberOfRows = static_cast< sal_Int32 >( + ceil( sqrt( static_cast< double >( nNumberOfEntries ) * fAspect ))); + nNumberOfColumns = nNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfRows ) )) + : 0; + } + + if(nNumberOfRows<=0) + return; + + // calculate maximum height for current row + std::vector< sal_Int32 > nMaxHeights( nNumberOfRows ); + sal_Int32 nRow = 0; + sal_Int32 nColumn = 0; + for( ; nRow < nNumberOfRows; ++nRow ) + { + sal_Int32 nMaxHeight = 0; + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nEntry = ( eExpansion == LegendExpansion_WIDE ) + ? (nColumn + nRow * nNumberOfColumns) + // HIGH or BALANCED + : (nRow + nColumn * nNumberOfRows); + if( nEntry < nNumberOfEntries ) + nMaxHeight = ::std::max( + nMaxHeight, nYOffset + aTextShapes[ nEntry ]->getSize().Height ); + } + nMaxHeights[ nRow ] = nMaxHeight; + } + + // place entries ordered in optimal-width columns + sal_Int32 nMaxYPos = 0; + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nMaxWidth = 0; + nCurrentYPos = nYPadding; + + for( nRow = 0; nRow < nNumberOfRows; ++nRow ) + { + sal_Int32 nEntry = ( eExpansion == LegendExpansion_WIDE ) + ? (nColumn + nRow * nNumberOfColumns) + // HIGH or BALANCED + : (nRow + nColumn * nNumberOfRows); + + if( nEntry >= nNumberOfEntries ) + break; + + // symbol + Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol ); + + if( xSymbol.is() ) + { + // Note: aspect ratio should always be 3:2 + + // set symbol size to 75% of maximum space + awt::Size aSymbolSize( + aMaxSymbolExtent.Width * 75 / 100, + aMaxSymbolExtent.Height * 75 / 100 ); + xSymbol->setSize( aSymbolSize ); + sal_Int32 nSymbolXPos = nCurrentXPos + ((aMaxSymbolExtent.Width - aSymbolSize.Width) / 2); + if( !bSymbolsLeftSide ) + nSymbolXPos = nSymbolXPos - aMaxSymbolExtent.Width; + + // #i109336# Improve auto positioning in chart + sal_Int32 nTextHeight = nMaxHeights[ nRow ] - nYOffset; + sal_Int32 nFontSize = static_cast< sal_Int32 >( fViewFontSize ); + sal_Int32 nMaxRowHeight = ( ( ( nTextHeight / nFontSize ) <= 1 ) ? nTextHeight : nFontSize ); + sal_Int32 nSymbolYPos = nCurrentYPos + ( ( nMaxRowHeight - aSymbolSize.Height ) / 2 ); + xSymbol->setPosition( awt::Point( nSymbolXPos, nSymbolYPos ) ); + } + + // position text shape + awt::Size aTextSize( aTextShapes[ nEntry ]->getSize()); + nMaxWidth = ::std::max( nMaxWidth, 2 * nXOffset + aMaxSymbolExtent.Width + aTextSize.Width ); + sal_Int32 nTextXPos = nCurrentXPos + aMaxSymbolExtent.Width; + if( !bSymbolsLeftSide ) + nTextXPos = nCurrentXPos - aMaxSymbolExtent.Width - aTextSize.Width; + aTextShapes[ nEntry ]->setPosition( awt::Point( nTextXPos, nCurrentYPos )); + + nCurrentYPos += nMaxHeights[ nRow ]; + nMaxYPos = ::std::max( nMaxYPos, nCurrentYPos ); + } + if( bSymbolsLeftSide ) + nCurrentXPos += nMaxWidth; + else + nCurrentXPos -= nMaxWidth; + } + + if( bSymbolsLeftSide ) + rOutLegendSize.Width = nCurrentXPos + nXPadding; + else + { + sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding); + rOutLegendSize.Width = nLegendWidth; + + awt::Point aPos(0,0); + for( sal_Int32 nEntry=0; nEntry<nNumberOfEntries; nEntry++ ) + { + Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol ); + aPos = xSymbol->getPosition(); + aPos.X += nLegendWidth; + xSymbol->setPosition( aPos ); + Reference< drawing::XShape > xText( aTextShapes[ nEntry ] ); + aPos = xText->getPosition(); + aPos.X += nLegendWidth; + xText->setPosition( aPos ); + } + } + rOutLegendSize.Height = nMaxYPos + nYPadding; +} + +// #i109336# Improve auto positioning in chart +sal_Int32 lcl_getLegendLeftRightMargin() +{ + return 210; // 1/100 mm +} + +// #i109336# Improve auto positioning in chart +sal_Int32 lcl_getLegendTopBottomMargin() +{ + return 185; // 1/100 mm +} + +chart2::RelativePosition lcl_getDefaultPosition( LegendPosition ePos, const awt::Rectangle& rOutAvailableSpace, const awt::Size & rPageSize ) +{ + chart2::RelativePosition aResult; + + switch( ePos ) + { + case LegendPosition_LINE_START: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) / + static_cast< double >( rPageSize.Width ) ); + aResult = chart2::RelativePosition( + fDefaultDistance, 0.5, drawing::Alignment_LEFT ); + } + break; + case LegendPosition_LINE_END: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) / + static_cast< double >( rPageSize.Width ) ); + aResult = chart2::RelativePosition( + 1.0 - fDefaultDistance, 0.5, drawing::Alignment_RIGHT ); + } + break; + case LegendPosition_PAGE_START: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) / + static_cast< double >( rPageSize.Height ) ); + double fDistance = (static_cast<double>(rOutAvailableSpace.Y)/static_cast<double>(rPageSize.Height)) + fDefaultDistance; + aResult = chart2::RelativePosition( + 0.5, fDistance, drawing::Alignment_TOP ); + } + break; + case LegendPosition_PAGE_END: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) / + static_cast< double >( rPageSize.Height ) ); + aResult = chart2::RelativePosition( + 0.5, 1.0 - fDefaultDistance, drawing::Alignment_BOTTOM ); + } + break; + + case LegendPosition_CUSTOM: + // to avoid warning + case LegendPosition_MAKE_FIXED_SIZE: + // nothing to be set + break; + } + + return aResult; +} + +/** @return + a point relative to the upper left corner that can be used for + XShape::setPosition() +*/ +awt::Point lcl_calculatePositionAndRemainingSpace( + awt::Rectangle & rRemainingSpace, + const awt::Size & rPageSize, + chart2::RelativePosition aRelPos, + LegendPosition ePos, + const awt::Size& aLegendSize ) +{ + // calculate position + awt::Point aResult( + static_cast< sal_Int32 >( aRelPos.Primary * rPageSize.Width ), + static_cast< sal_Int32 >( aRelPos.Secondary * rPageSize.Height )); + + aResult = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + aResult, aLegendSize, aRelPos.Anchor ); + + // adapt rRemainingSpace if LegendPosition is not CUSTOM + // #i109336# Improve auto positioning in chart + sal_Int32 nXDistance = lcl_getLegendLeftRightMargin(); + sal_Int32 nYDistance = lcl_getLegendTopBottomMargin(); + switch( ePos ) + { + case LegendPosition_LINE_START: + { + sal_Int32 nExtent = aLegendSize.Width; + rRemainingSpace.Width -= ( nExtent + nXDistance ); + rRemainingSpace.X += ( nExtent + nXDistance ); + } + break; + case LegendPosition_LINE_END: + { + rRemainingSpace.Width -= ( aLegendSize.Width + nXDistance ); + } + break; + case LegendPosition_PAGE_START: + { + sal_Int32 nExtent = aLegendSize.Height; + rRemainingSpace.Height -= ( nExtent + nYDistance ); + rRemainingSpace.Y += ( nExtent + nYDistance ); + } + break; + case LegendPosition_PAGE_END: + { + rRemainingSpace.Height -= ( aLegendSize.Height + nYDistance ); + } + break; + + default: + // nothing + break; + } + + // adjust the legend position. Esp. for old files that had slightly smaller legends + const sal_Int32 nEdgeDistance( 30 ); + if( aResult.X + aLegendSize.Width > rPageSize.Width ) + { + sal_Int32 nNewX( (rPageSize.Width - aLegendSize.Width) - nEdgeDistance ); + if( nNewX > rPageSize.Width / 4 ) + aResult.X = nNewX; + } + if( aResult.Y + aLegendSize.Height > rPageSize.Height ) + { + sal_Int32 nNewY( (rPageSize.Height - aLegendSize.Height) - nEdgeDistance ); + if( nNewY > rPageSize.Height / 4 ) + aResult.Y = nNewY; + } + + return aResult; +} + +template< class T > +void lcl_appendSeqToVector( const Sequence< T > & rSource, ::std::vector< T > & rDest ) +{ + const sal_Int32 nCount = rSource.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + rDest.push_back( rSource[ i ] ); +} + +bool lcl_shouldSymbolsBePlacedOnTheLeftSide( const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode ) +{ + bool bSymbolsLeftSide = true; + try + { + if( SvtLanguageOptions().IsCTLFontEnabled() ) + { + if(xLegendProp.is()) + { + sal_Int16 nWritingMode=-1; + if( (xLegendProp->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode) ) + { + if( nWritingMode == text::WritingMode2::PAGE ) + nWritingMode = nDefaultWritingMode; + if( nWritingMode == text::WritingMode2::RL_TB ) + bSymbolsLeftSide=false; + } + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return bSymbolsLeftSide; +} + +} // anonymous namespace + +VLegend::VLegend( + const Reference< XLegend > & xLegend, + const Reference< uno::XComponentContext > & xContext, + const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ) : + m_xLegend( xLegend ), + m_xContext( xContext ), + m_aLegendEntryProviderList( rLegendEntryProviderList ) +{ +} + +// ---------------------------------------- + +void SAL_CALL VLegend::init( + const Reference< drawing::XShapes >& xTargetPage, + const Reference< lang::XMultiServiceFactory >& xFactory, + const Reference< frame::XModel >& xModel ) +{ + m_xTarget = xTargetPage; + m_xShapeFactory = xFactory; + m_xModel = xModel; +} + +// ---------------------------------------- + +void VLegend::setDefaultWritingMode( sal_Int16 nDefaultWritingMode ) +{ + m_nDefaultWritingMode = nDefaultWritingMode; +} + +// ---------------------------------------- + +// static +bool VLegend::isVisible( const Reference< XLegend > & xLegend ) +{ + if( ! xLegend.is()) + return sal_False; + + sal_Bool bShow = sal_False; + try + { + Reference< beans::XPropertySet > xLegendProp( xLegend, uno::UNO_QUERY_THROW ); + xLegendProp->getPropertyValue( C2U( "Show" )) >>= bShow; + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return bShow; +} + +// ---------------------------------------- + +void VLegend::createShapes( + const awt::Size & rAvailableSpace, + const awt::Size & rPageSize ) +{ + if(! (m_xLegend.is() && + m_xShapeFactory.is() && + m_xTarget.is())) + return; + + try + { + //create shape and add to page + m_xShape.set( m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY ); + m_xTarget->add( m_xShape ); + + // set name to enable selection + { + OUString aLegendParticle( ObjectIdentifier::createParticleForLegend( m_xLegend, m_xModel ) ); + ShapeFactory::setShapeName( m_xShape, ObjectIdentifier::createClassifiedIdentifierForParticle( aLegendParticle ) ); + } + + // create and insert sub-shapes + Reference< drawing::XShapes > xLegendContainer( m_xShape, uno::UNO_QUERY ); + if( xLegendContainer.is()) + { + Reference< drawing::XShape > xBorder( + m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + + // for quickly setting properties + tPropertyValues aLineFillProperties; + tPropertyValues aTextProperties; + + // limit the width of texts to 30% of the total available width + // #i109336# Improve auto positioning in chart + sal_Int32 nMaxLabelWidth = rAvailableSpace.Width * 3 / 10; + Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY ); + LegendExpansion eExpansion = LegendExpansion_HIGH; + if( xLegendProp.is()) + { + // get Expansion property + xLegendProp->getPropertyValue( C2U( "Expansion" )) >>= eExpansion; + if( eExpansion == LegendExpansion_WIDE ) + { + //#i80377# + nMaxLabelWidth = (rAvailableSpace.Width * 5) / 6;//completely correct would be available width minus symbol size minus distances to page ... + } + + lcl_getProperties( xLegendProp, aLineFillProperties, aTextProperties, nMaxLabelWidth, + rPageSize ); + } + + if( xBorder.is()) + { + xLegendContainer->add( xBorder ); + + // apply legend properties + PropertyMapper::setMultiProperties( + aLineFillProperties.first, aLineFillProperties.second, + Reference< beans::XPropertySet >( xBorder, uno::UNO_QUERY )); + + //because of this name this border will be used for marking the legend + ShapeFactory(m_xShapeFactory).setShapeName( xBorder, C2U("MarkHandles") ); + } + + // create entries + tViewLegendEntryContainer aViewEntries; + { + ::std::vector< LegendEntryProvider* >::const_iterator aIter = m_aLegendEntryProviderList.begin(); + const ::std::vector< LegendEntryProvider* >::const_iterator aEnd = m_aLegendEntryProviderList.end(); + for( ; aIter != aEnd; aIter++ ) + { + LegendEntryProvider* pLegendEntryProvider( *aIter ); + if( pLegendEntryProvider ) + { + lcl_appendSeqToVector< ViewLegendEntry >( + pLegendEntryProvider->createLegendEntries( eExpansion, xLegendProp, xLegendContainer, m_xShapeFactory, m_xContext ) + , aViewEntries ); + } + } + } + + bool bSymbolsLeftSide = lcl_shouldSymbolsBePlacedOnTheLeftSide( xLegendProp, m_nDefaultWritingMode ); + + // place entries + awt::Size aLegendSize; + lcl_placeLegendEntries( aViewEntries, eExpansion, bSymbolsLeftSide + , xLegendProp, aTextProperties + , xLegendContainer, m_xShapeFactory, m_xContext + , rAvailableSpace, rPageSize, aLegendSize ); + + if( xBorder.is()) + xBorder->setSize( aLegendSize ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +// ---------------------------------------- + +void VLegend::changePosition( + awt::Rectangle & rOutAvailableSpace, + const awt::Size & rPageSize ) +{ + if(! m_xShape.is()) + return; + + try + { + // determine position and alignment depending on default position + awt::Size aLegendSize = m_xShape->getSize(); + Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY_THROW ); + chart2::RelativePosition aRelativePosition; + + bool bAutoPosition = + ! (xLegendProp->getPropertyValue( C2U( "RelativePosition" )) >>= aRelativePosition); + + LegendPosition ePos = LegendPosition_CUSTOM; + xLegendProp->getPropertyValue( C2U( "AnchorPosition" )) >>= ePos; + + //calculate position + if( bAutoPosition ) + { + // auto position: relative to remaining space + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + awt::Point aPos = lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + m_xShape->setPosition( aPos ); + } + else + { + // manual position: relative to whole page + awt::Rectangle aAvailableSpace( 0, 0, rPageSize.Width, rPageSize.Height ); + awt::Point aPos = lcl_calculatePositionAndRemainingSpace( + aAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + m_xShape->setPosition( aPos ); + + if( ePos != LegendPosition_CUSTOM ) + { + // calculate remaining space as if having autoposition: + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. |