merge the formfield patch from ooo-build
[ooovba.git] / chart2 / source / view / main / VLegend.cxx
blob3ecff8bd463fb968668203808074cec5b909d464
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: VLegend.cxx,v $
10 * $Revision: 1.40 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
33 #include "VLegend.hxx"
34 #include "macros.hxx"
35 #include "PropertyMapper.hxx"
36 #include "CommonConverters.hxx"
37 #include "ObjectIdentifier.hxx"
38 #include "RelativePositionHelper.hxx"
39 #include "ShapeFactory.hxx"
40 #include "RelativeSizeHelper.hxx"
41 #include "LegendEntryProvider.hxx"
42 #include <com/sun/star/text/XTextRange.hpp>
43 #include <com/sun/star/text/WritingMode2.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/beans/XPropertyState.hpp>
46 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
47 #include <com/sun/star/drawing/LineJoint.hpp>
48 #include <com/sun/star/chart2/LegendExpansion.hpp>
49 #include <com/sun/star/chart2/LegendPosition.hpp>
50 #include <com/sun/star/chart2/RelativePosition.hpp>
51 #include <rtl/ustrbuf.hxx>
52 #include <svtools/languageoptions.hxx>
54 #include <vector>
55 #include <algorithm>
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::chart2;
60 using ::com::sun::star::uno::Reference;
61 using ::com::sun::star::uno::Sequence;
62 using ::rtl::OUString;
63 using ::rtl::OUStringBuffer;
65 //.............................................................................
66 namespace chart
68 //.............................................................................
70 namespace
73 typedef ::std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues;
75 typedef ::std::vector< ViewLegendEntry > tViewLegendEntryContainer;
77 double lcl_CalcViewFontSize(
78 const Reference< beans::XPropertySet > & xProp,
79 const awt::Size & rReferenceSize )
81 double fResult = 10.0;
83 awt::Size aPropRefSize;
84 float fFontHeight( 0.0 );
85 if( xProp.is() && ( xProp->getPropertyValue( C2U( "CharHeight" )) >>= fFontHeight ))
87 fResult = fFontHeight;
88 try
90 if( (xProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) &&
91 (aPropRefSize.Height > 0))
93 // todo: find out if asian text is really used
94 // Reference< beans::XPropertySetInfo >xInfo( xProp, uno::UNO_QUERY );
95 // float fFontHeight2 = fFontHeight;
96 // if( xInfo.is() &&
97 // xInfo->hasPropertyByName(C2U("CharHeightAsian")) &&
98 // (xProp->getPropertyValue(C2U("CharHeightAsian")) >>= fFontHeight2) &&
99 // fFontHeight2 > fFontHeight )
100 // {
101 // fFontHeight = fFontHeight2;
102 // }
104 // if( xInfo.is() &&
105 // xInfo->hasPropertyByName(C2U("CharHeightComplex")) &&
106 // (xProp->getPropertyValue(C2U("CharHeightComplex")) >>= fFontHeight2) &&
107 // fFontHeight2 > fFontHeight )
108 // {
109 // fFontHeight = fFontHeight2;
110 // }
112 fResult = ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize );
115 catch( const uno::Exception & ex )
117 ASSERT_EXCEPTION( ex );
121 // pt -> 1/100th mm
122 return (fResult * (2540.0 / 72.0));
125 void lcl_getProperties(
126 const Reference< beans::XPropertySet > & xLegendProp,
127 tPropertyValues & rOutLineFillProperties,
128 tPropertyValues & rOutTextProperties,
129 sal_Int32 nMaxLabelWidth,
130 const awt::Size & rReferenceSize )
132 // Get Line- and FillProperties from model legend
133 if( xLegendProp.is())
135 // set rOutLineFillProperties
136 ::chart::tPropertyNameValueMap aLineFillValueMap;
137 ::chart::PropertyMapper::getValueMap( aLineFillValueMap, ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xLegendProp );
139 aLineFillValueMap[ C2U("LineJoint") ] = uno::makeAny( drawing::LineJoint_ROUND );
141 ::chart::PropertyMapper::getMultiPropertyListsFromValueMap(
142 rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap );
144 // set rOutTextProperties
145 ::chart::tPropertyNameValueMap aTextValueMap;
146 ::chart::PropertyMapper::getValueMap( aTextValueMap, ::chart::PropertyMapper::getPropertyNameMapForCharacterProperties(), xLegendProp );
148 drawing::TextHorizontalAdjust eHorizAdjust( drawing::TextHorizontalAdjust_LEFT );
149 aTextValueMap[ C2U("TextAutoGrowHeight") ] = uno::makeAny( sal_True );
150 aTextValueMap[ C2U("TextAutoGrowWidth") ] = uno::makeAny( sal_True );
151 aTextValueMap[ C2U("TextHorizontalAdjust") ] = uno::makeAny( eHorizAdjust );
152 aTextValueMap[ C2U("TextMaximumFrameWidth") ] = uno::makeAny( nMaxLabelWidth );
154 // recalculate font size
155 awt::Size aPropRefSize;
156 float fFontHeight( 0.0 );
157 if( (xLegendProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) &&
158 (aPropRefSize.Height > 0) &&
159 (aTextValueMap[ C2U("CharHeight") ] >>= fFontHeight) )
161 aTextValueMap[ C2U("CharHeight") ] = uno::makeAny(
162 static_cast< float >(
163 ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )));
165 if( aTextValueMap[ C2U("CharHeightAsian") ] >>= fFontHeight )
167 aTextValueMap[ C2U("CharHeightAsian") ] = uno::makeAny(
168 static_cast< float >(
169 ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )));
171 if( aTextValueMap[ C2U("CharHeightComplex") ] >>= fFontHeight )
173 aTextValueMap[ C2U("CharHeightComplex") ] = uno::makeAny(
174 static_cast< float >(
175 ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )));
179 ::chart::PropertyMapper::getMultiPropertyListsFromValueMap(
180 rOutTextProperties.first, rOutTextProperties.second, aTextValueMap );
184 awt::Size lcl_createTextShapes(
185 const tViewLegendEntryContainer & rEntries,
186 const Reference< lang::XMultiServiceFactory > & xShapeFactory,
187 const Reference< drawing::XShapes > & xTarget,
188 ::std::vector< Reference< drawing::XShape > > & rOutTextShapes,
189 const tPropertyValues & rTextProperties )
191 awt::Size aResult;
193 for( tViewLegendEntryContainer::const_iterator aIt( rEntries.begin());
194 aIt != rEntries.end(); ++aIt )
198 // create label shape
199 Reference< drawing::XShape > xGroupShapeForSingleEntry(
200 xShapeFactory->createInstance(
201 C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY_THROW );
202 Reference< drawing::XShape >xEntry(
203 xShapeFactory->createInstance(
204 C2U( "com.sun.star.drawing.TextShape" )), uno::UNO_QUERY_THROW );
205 xTarget->add( xGroupShapeForSingleEntry );
207 Reference< drawing::XShapes > xGroup( xGroupShapeForSingleEntry, uno::UNO_QUERY_THROW );
208 xGroup->add( xEntry );
210 // set label text
211 Sequence< Reference< XFormattedString > > aLabelSeq = (*aIt).aLabel;
212 for( sal_Int32 i = 0; i < aLabelSeq.getLength(); ++i )
214 // todo: support more than one text range
215 if( i == 1 )
216 break;
218 Reference< text::XTextRange > xRange( xEntry, uno::UNO_QUERY );
219 OUString aLabelString( aLabelSeq[i]->getString());
220 // workaround for Issue #i67540#
221 if( !aLabelString.getLength())
222 aLabelString = C2U(" ");
223 if( xRange.is())
224 xRange->setString( aLabelString );
226 PropertyMapper::setMultiProperties(
227 rTextProperties.first, rTextProperties.second,
228 Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY ));
230 // adapt max-extent
231 awt::Size aCurrSize( xEntry->getSize());
232 aResult.Width = ::std::max( aResult.Width, aCurrSize.Width );
233 aResult.Height = ::std::max( aResult.Height, aCurrSize.Height );
236 rOutTextShapes.push_back( xGroupShapeForSingleEntry );
238 catch( uno::Exception & ex )
240 ASSERT_EXCEPTION( ex );
244 return aResult;
248 void lcl_placeLegendEntries(
249 const tViewLegendEntryContainer & rEntries,
250 LegendExpansion eExpansion,
251 bool bSymbolsLeftSide,
252 const Reference< beans::XPropertySet > & xProperties,
253 tPropertyValues & rTextProperties,
254 const Reference< drawing::XShapes > & xTarget,
255 const Reference< lang::XMultiServiceFactory > & xShapeFactory,
256 const Reference< uno::XComponentContext > & /* xContext */,
257 const awt::Size & rAvailableSpace,
258 const awt::Size & rPageSize,
259 awt::Size & rOutLegendSize )
261 double fViewFontSize = lcl_CalcViewFontSize( xProperties, rPageSize );
263 // padding as percentage of the font height
264 double fXPadding = (1.0 / 5.0);
265 double fYPadding = (1.0 / 3.0);
266 double fXOffset = (1.0 / 5.0);
267 double fYOffset = (1.0 / 5.0);
269 const sal_Int32 nXPadding = static_cast< sal_Int32 >( fViewFontSize * fXPadding );
270 const sal_Int32 nYPadding = static_cast< sal_Int32 >( fViewFontSize * fYPadding );
271 const sal_Int32 nXOffset = static_cast< sal_Int32 >( fViewFontSize * fXOffset );
272 const sal_Int32 nYOffset = static_cast< sal_Int32 >( fViewFontSize * fYOffset );
274 ::std::vector< Reference< drawing::XShape > > aTextShapes;
275 awt::Size aMaxEntryExtent = lcl_createTextShapes(
276 rEntries, xShapeFactory, xTarget, aTextShapes, rTextProperties );
277 OSL_ASSERT( aTextShapes.size() == rEntries.size());
279 awt::Size aMaxSymbolExtent( static_cast< sal_Int32 >( fViewFontSize * 3.0 / 2.0 ),
280 static_cast< sal_Int32 >( fViewFontSize ));
281 sal_Int32 nCurrentXPos = nXPadding;
282 sal_Int32 nCurrentYPos = nYPadding;
283 sal_Int32 nMaxEntryWidth = 2 * nXOffset + aMaxSymbolExtent.Width + aMaxEntryExtent.Width;
284 sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height;
285 sal_Int32 nNumberOfEntries = rEntries.size();
287 if( !bSymbolsLeftSide )
288 nCurrentXPos = -nXPadding;
290 sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0;
292 // determine layout depending on LegendExpansion
293 if( eExpansion == LegendExpansion_HIGH )
295 sal_Int32 nMaxNumberOfRows = nMaxEntryHeight
296 ? (rAvailableSpace.Height - 2*nYPadding ) / nMaxEntryHeight
297 : 0;
299 nNumberOfColumns = nMaxNumberOfRows
300 ? static_cast< sal_Int32 >(
301 ceil( static_cast< double >( nNumberOfEntries ) /
302 static_cast< double >( nMaxNumberOfRows ) ))
303 : 0;
304 nNumberOfRows = nNumberOfColumns
305 ? static_cast< sal_Int32 >(
306 ceil( static_cast< double >( nNumberOfEntries ) /
307 static_cast< double >( nNumberOfColumns ) ))
308 : 0;
310 else if( eExpansion == LegendExpansion_WIDE )
312 sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth
313 ? (rAvailableSpace.Width - 2*nXPadding ) / nMaxEntryWidth
314 : 0;
316 nNumberOfRows = nMaxNumberOfColumns
317 ? static_cast< sal_Int32 >(
318 ceil( static_cast< double >( nNumberOfEntries ) /
319 static_cast< double >( nMaxNumberOfColumns ) ))
320 : 0;
321 nNumberOfColumns = nNumberOfRows
322 ? static_cast< sal_Int32 >(
323 ceil( static_cast< double >( nNumberOfEntries ) /
324 static_cast< double >( nNumberOfRows ) ))
325 : 0;
327 else // LegendExpansion_BALANCED
329 double fAspect = nMaxEntryHeight
330 ? static_cast< double >( nMaxEntryWidth ) / static_cast< double >( nMaxEntryHeight )
331 : 0.0;
333 nNumberOfRows = static_cast< sal_Int32 >(
334 ceil( sqrt( static_cast< double >( nNumberOfEntries ) * fAspect )));
335 nNumberOfColumns = nNumberOfRows
336 ? static_cast< sal_Int32 >(
337 ceil( static_cast< double >( nNumberOfEntries ) /
338 static_cast< double >( nNumberOfRows ) ))
339 : 0;
342 if(nNumberOfRows<=0)
343 return;
345 // calculate maximum height for current row
346 std::vector< sal_Int32 > nMaxHeights( nNumberOfRows );
347 sal_Int32 nRow = 0;
348 sal_Int32 nColumn = 0;
349 for( ; nRow < nNumberOfRows; ++nRow )
351 sal_Int32 nMaxHeight = 0;
352 for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn )
354 sal_Int32 nEntry = ( eExpansion == LegendExpansion_WIDE )
355 ? (nColumn + nRow * nNumberOfColumns)
356 // HIGH or BALANCED
357 : (nRow + nColumn * nNumberOfRows);
358 if( nEntry < nNumberOfEntries )
359 nMaxHeight = ::std::max(
360 nMaxHeight, nYOffset + aTextShapes[ nEntry ]->getSize().Height );
362 nMaxHeights[ nRow ] = nMaxHeight;
365 // place entries ordered in optimal-width columns
366 sal_Int32 nMaxYPos = 0;
367 for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn )
369 sal_Int32 nMaxWidth = 0;
370 nCurrentYPos = nYPadding;
372 for( nRow = 0; nRow < nNumberOfRows; ++nRow )
374 sal_Int32 nEntry = ( eExpansion == LegendExpansion_WIDE )
375 ? (nColumn + nRow * nNumberOfColumns)
376 // HIGH or BALANCED
377 : (nRow + nColumn * nNumberOfRows);
379 if( nEntry >= nNumberOfEntries )
380 break;
382 // symbol
383 Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol );
385 if( xSymbol.is() )
387 // Note: aspect ratio should always be 3:2
389 // set symbol size to 75% of maximum space
390 awt::Size aSymbolSize(
391 aMaxSymbolExtent.Width * 75 / 100,
392 aMaxSymbolExtent.Height * 75 / 100 );
393 xSymbol->setSize( aSymbolSize );
394 sal_Int32 nSymbolXPos = nCurrentXPos + ((aMaxSymbolExtent.Width - aSymbolSize.Width) / 2);
395 if( !bSymbolsLeftSide )
396 nSymbolXPos = nSymbolXPos - aMaxSymbolExtent.Width;
397 xSymbol->setPosition( awt::Point( nSymbolXPos,
398 nCurrentYPos + ((aMaxSymbolExtent.Height - aSymbolSize.Height) / 2)));
401 // position text shape
402 awt::Size aTextSize( aTextShapes[ nEntry ]->getSize());
403 nMaxWidth = ::std::max( nMaxWidth, 2 * nXOffset + aMaxSymbolExtent.Width + aTextSize.Width );
404 sal_Int32 nTextXPos = nCurrentXPos + aMaxSymbolExtent.Width;
405 if( !bSymbolsLeftSide )
406 nTextXPos = nCurrentXPos - aMaxSymbolExtent.Width - aTextSize.Width;
407 aTextShapes[ nEntry ]->setPosition( awt::Point( nTextXPos, nCurrentYPos ));
409 nCurrentYPos += nMaxHeights[ nRow ];
410 nMaxYPos = ::std::max( nMaxYPos, nCurrentYPos );
412 if( bSymbolsLeftSide )
413 nCurrentXPos += nMaxWidth;
414 else
415 nCurrentXPos -= nMaxWidth;
418 if( bSymbolsLeftSide )
419 rOutLegendSize.Width = nCurrentXPos + nXPadding;
420 else
422 sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding);
423 rOutLegendSize.Width = nLegendWidth;
425 awt::Point aPos(0,0);
426 for( sal_Int32 nEntry=0; nEntry<nNumberOfEntries; nEntry++ )
428 Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol );
429 aPos = xSymbol->getPosition();
430 aPos.X += nLegendWidth;
431 xSymbol->setPosition( aPos );
432 Reference< drawing::XShape > xText( aTextShapes[ nEntry ] );
433 aPos = xText->getPosition();
434 aPos.X += nLegendWidth;
435 xText->setPosition( aPos );
438 rOutLegendSize.Height = nMaxYPos + nYPadding;
441 double lcl_getPageLayoutDistancePercentage()
443 return 0.02;
446 chart2::RelativePosition lcl_getDefaultPosition( LegendPosition ePos, const awt::Rectangle& rOutAvailableSpace, const awt::Size & rPageSize )
448 // shift legend about 2% of page size into the primary direction by default
449 const double fDefaultDistance = lcl_getPageLayoutDistancePercentage();
450 chart2::RelativePosition aResult;
452 switch( ePos )
454 case LegendPosition_LINE_START:
455 aResult = chart2::RelativePosition(
456 fDefaultDistance, 0.5, drawing::Alignment_LEFT );
457 break;
458 case LegendPosition_LINE_END:
459 aResult = chart2::RelativePosition(
460 1.0 - fDefaultDistance, 0.5, drawing::Alignment_RIGHT );
461 break;
462 case LegendPosition_PAGE_START:
464 double fDistance = (static_cast<double>(rOutAvailableSpace.Y)/static_cast<double>(rPageSize.Height)) + fDefaultDistance;
465 aResult = chart2::RelativePosition(
466 0.5, fDistance, drawing::Alignment_TOP );
468 break;
469 case LegendPosition_PAGE_END:
470 aResult = chart2::RelativePosition(
471 0.5, 1.0 - fDefaultDistance, drawing::Alignment_BOTTOM );
472 break;
474 case LegendPosition_CUSTOM:
475 // to avoid warning
476 case LegendPosition_MAKE_FIXED_SIZE:
477 // nothing to be set
478 break;
481 return aResult;
484 /** @return
485 a point relative to the upper left corner that can be used for
486 XShape::setPosition()
488 awt::Point lcl_calculatePositionAndRemainingSpace(
489 awt::Rectangle & rRemainingSpace,
490 const awt::Size & rPageSize,
491 chart2::RelativePosition aRelPos,
492 LegendPosition ePos,
493 const awt::Size& aLegendSize )
495 // calculate position
496 awt::Point aResult(
497 static_cast< sal_Int32 >( aRelPos.Primary * rPageSize.Width ),
498 static_cast< sal_Int32 >( aRelPos.Secondary * rPageSize.Height ));
500 aResult = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
501 aResult, aLegendSize, aRelPos.Anchor );
503 // adapt rRemainingSpace if LegendPosition is not CUSTOM
504 sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage());
505 sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage());
506 rRemainingSpace.Width-=nXDistance;
507 rRemainingSpace.Height-=nYDistance;
508 switch( ePos )
510 case LegendPosition_LINE_START:
512 sal_Int32 nExtent = aLegendSize.Width;
513 rRemainingSpace.Width -= nExtent;
514 rRemainingSpace.X += ( nExtent + nXDistance );
516 break;
517 case LegendPosition_LINE_END:
518 rRemainingSpace.Width -= ( aLegendSize.Width );
519 break;
520 case LegendPosition_PAGE_START:
522 sal_Int32 nExtent = aLegendSize.Height;
523 rRemainingSpace.Height -= nExtent;
524 rRemainingSpace.Y += ( nExtent + nYDistance );
526 break;
527 case LegendPosition_PAGE_END:
528 rRemainingSpace.Height -= ( aLegendSize.Height );
529 break;
531 default:
532 // nothing
533 break;
536 // adjust the legend position. Esp. for old files that had slightly smaller legends
537 const sal_Int32 nEdgeDistance( 30 );
538 if( aResult.X + aLegendSize.Width > rPageSize.Width )
540 sal_Int32 nNewX( (rPageSize.Width - aLegendSize.Width) - nEdgeDistance );
541 if( nNewX > rPageSize.Width / 4 )
542 aResult.X = nNewX;
544 if( aResult.Y + aLegendSize.Height > rPageSize.Height )
546 sal_Int32 nNewY( (rPageSize.Height - aLegendSize.Height) - nEdgeDistance );
547 if( nNewY > rPageSize.Height / 4 )
548 aResult.Y = nNewY;
551 return aResult;
554 template< class T >
555 void lcl_appendSeqToVector( const Sequence< T > & rSource, ::std::vector< T > & rDest )
557 const sal_Int32 nCount = rSource.getLength();
558 for( sal_Int32 i = 0; i < nCount; ++i )
559 rDest.push_back( rSource[ i ] );
562 bool lcl_shouldSymbolsBePlacedOnTheLeftSide( const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode )
564 bool bSymbolsLeftSide = true;
567 if( SvtLanguageOptions().IsCTLFontEnabled() )
569 if(xLegendProp.is())
571 sal_Int16 nWritingMode=-1;
572 if( (xLegendProp->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode) )
574 if( nWritingMode == text::WritingMode2::PAGE )
575 nWritingMode = nDefaultWritingMode;
576 if( nWritingMode == text::WritingMode2::RL_TB )
577 bSymbolsLeftSide=false;
582 catch( uno::Exception & ex )
584 ASSERT_EXCEPTION( ex );
586 return bSymbolsLeftSide;
589 } // anonymous namespace
591 VLegend::VLegend(
592 const Reference< XLegend > & xLegend,
593 const Reference< uno::XComponentContext > & xContext,
594 const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ) :
595 m_xLegend( xLegend ),
596 m_xContext( xContext ),
597 m_aLegendEntryProviderList( rLegendEntryProviderList )
601 // ----------------------------------------
603 void SAL_CALL VLegend::init(
604 const Reference< drawing::XShapes >& xTargetPage,
605 const Reference< lang::XMultiServiceFactory >& xFactory,
606 const Reference< frame::XModel >& xModel )
608 m_xTarget = xTargetPage;
609 m_xShapeFactory = xFactory;
610 m_xModel = xModel;
613 // ----------------------------------------
615 void VLegend::setDefaultWritingMode( sal_Int16 nDefaultWritingMode )
617 m_nDefaultWritingMode = nDefaultWritingMode;
620 // ----------------------------------------
622 // static
623 bool VLegend::isVisible( const Reference< XLegend > & xLegend )
625 if( ! xLegend.is())
626 return sal_False;
628 sal_Bool bShow = sal_False;
631 Reference< beans::XPropertySet > xLegendProp( xLegend, uno::UNO_QUERY_THROW );
632 xLegendProp->getPropertyValue( C2U( "Show" )) >>= bShow;
634 catch( uno::Exception & ex )
636 ASSERT_EXCEPTION( ex );
639 return bShow;
642 // ----------------------------------------
644 void VLegend::createShapes(
645 const awt::Size & rAvailableSpace,
646 const awt::Size & rPageSize )
648 if(! (m_xLegend.is() &&
649 m_xShapeFactory.is() &&
650 m_xTarget.is()))
651 return;
655 //create shape and add to page
656 m_xShape.set( m_xShapeFactory->createInstance(
657 C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY );
658 m_xTarget->add( m_xShape );
660 // set name to enable selection
662 OUString aLegendParticle( ObjectIdentifier::createParticleForLegend( m_xLegend, m_xModel ) );
663 ShapeFactory::setShapeName( m_xShape, ObjectIdentifier::createClassifiedIdentifierForParticle( aLegendParticle ) );
666 // create and insert sub-shapes
667 Reference< drawing::XShapes > xLegendContainer( m_xShape, uno::UNO_QUERY );
668 if( xLegendContainer.is())
670 Reference< drawing::XShape > xBorder(
671 m_xShapeFactory->createInstance(
672 C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY );
674 // for quickly setting properties
675 tPropertyValues aLineFillProperties;
676 tPropertyValues aTextProperties;
678 // limit the width of texts to 20% of the total available width
679 sal_Int32 nMaxLabelWidth = rAvailableSpace.Width / 5;
680 Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY );
681 LegendExpansion eExpansion = LegendExpansion_HIGH;
682 if( xLegendProp.is())
684 lcl_getProperties( xLegendProp, aLineFillProperties, aTextProperties, nMaxLabelWidth,
685 rPageSize );
687 // get Expansion property
688 xLegendProp->getPropertyValue( C2U( "Expansion" )) >>= eExpansion;
691 if( xBorder.is())
693 xLegendContainer->add( xBorder );
695 // apply legend properties
696 PropertyMapper::setMultiProperties(
697 aLineFillProperties.first, aLineFillProperties.second,
698 Reference< beans::XPropertySet >( xBorder, uno::UNO_QUERY ));
700 //because of this name this border will be used for marking the legend
701 ShapeFactory(m_xShapeFactory).setShapeName( xBorder, C2U("MarkHandles") );
704 // create entries
705 tViewLegendEntryContainer aViewEntries;
707 ::std::vector< LegendEntryProvider* >::const_iterator aIter = m_aLegendEntryProviderList.begin();
708 const ::std::vector< LegendEntryProvider* >::const_iterator aEnd = m_aLegendEntryProviderList.end();
709 for( ; aIter != aEnd; aIter++ )
711 LegendEntryProvider* pLegendEntryProvider( *aIter );
712 if( pLegendEntryProvider )
714 lcl_appendSeqToVector< ViewLegendEntry >(
715 pLegendEntryProvider->createLegendEntries( eExpansion, xLegendProp, xLegendContainer, m_xShapeFactory, m_xContext )
716 , aViewEntries );
721 bool bSymbolsLeftSide = lcl_shouldSymbolsBePlacedOnTheLeftSide( xLegendProp, m_nDefaultWritingMode );
723 // place entries
724 awt::Size aLegendSize;
725 lcl_placeLegendEntries( aViewEntries, eExpansion, bSymbolsLeftSide
726 , xLegendProp, aTextProperties
727 , xLegendContainer, m_xShapeFactory, m_xContext
728 , rAvailableSpace, rPageSize, aLegendSize );
730 if( xBorder.is())
731 xBorder->setSize( aLegendSize );
734 catch( uno::Exception & ex )
736 ASSERT_EXCEPTION( ex );
740 // ----------------------------------------
742 void VLegend::changePosition(
743 awt::Rectangle & rOutAvailableSpace,
744 const awt::Size & rPageSize )
746 if(! m_xShape.is())
747 return;
751 // determine position and alignment depending on default position
752 awt::Size aLegendSize = m_xShape->getSize();
753 Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY_THROW );
754 chart2::RelativePosition aRelativePosition;
756 bool bAutoPosition =
757 ! (xLegendProp->getPropertyValue( C2U( "RelativePosition" )) >>= aRelativePosition);
759 LegendPosition ePos = LegendPosition_CUSTOM;
760 xLegendProp->getPropertyValue( C2U( "AnchorPosition" )) >>= ePos;
762 //calculate position
763 if( bAutoPosition )
765 // auto position: relative to remaining space
766 aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize );
767 awt::Point aPos = lcl_calculatePositionAndRemainingSpace(
768 rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize );
769 m_xShape->setPosition( aPos );
771 else
773 // manual position: relative to whole page
774 awt::Rectangle aAvailableSpace( 0, 0, rPageSize.Width, rPageSize.Height );
775 awt::Point aPos = lcl_calculatePositionAndRemainingSpace(
776 aAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize );
777 m_xShape->setPosition( aPos );
779 if( ePos != LegendPosition_CUSTOM )
781 // calculate remaining space as if having autoposition:
782 aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize );
783 lcl_calculatePositionAndRemainingSpace(
784 rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize );
788 catch( uno::Exception & ex )
790 ASSERT_EXCEPTION( ex );
794 //.............................................................................
795 } //namespace chart
796 //.............................................................................