32#include <com/sun/star/text/WritingMode2.hpp>
33#include <com/sun/star/beans/XPropertySet.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 <com/sun/star/chart2/RelativeSize.hpp>
40#include <com/sun/star/chart2/XFormattedString2.hpp>
41#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
42#include <com/sun/star/chart2/data/PivotTableFieldEntry.hpp>
43#include <rtl/math.hxx>
55using ::com::sun::star::uno::Reference;
56using ::com::sun::star::uno::Sequence;
64typedef std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues;
66double lcl_CalcViewFontSize(
67 const Reference< beans::XPropertySet > & xProp,
68 const awt::Size & rReferenceSize )
70 double fResult = 10.0;
72 float fFontHeight( 0.0 );
73 if( xProp.is() && ( xProp->getPropertyValue(
"CharHeight") >>= fFontHeight ))
75 fResult = fFontHeight;
78 awt::Size aPropRefSize;
79 if( (xProp->getPropertyValue(
"ReferencePageSize") >>= aPropRefSize) &&
80 (aPropRefSize.Height > 0))
85 catch(
const uno::Exception & )
94void lcl_getProperties(
95 const Reference< beans::XPropertySet > & xLegendProp,
96 tPropertyValues & rOutLineFillProperties,
97 tPropertyValues & rOutTextProperties,
98 const awt::Size & rReferenceSize )
101 if( !xLegendProp.is())
108 aLineFillValueMap[
"LineJoint" ] <<= drawing::LineJoint_ROUND;
111 rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap );
117 aTextValueMap[
"TextAutoGrowHeight" ] <<=
true;
118 aTextValueMap[
"TextAutoGrowWidth" ] <<=
true;
119 aTextValueMap[
"TextHorizontalAdjust" ] <<= drawing::TextHorizontalAdjust_LEFT;
120 aTextValueMap[
"TextMaximumFrameWidth" ] <<= rReferenceSize.Width;
123 awt::Size aPropRefSize;
124 float fFontHeight( 0.0 );
125 if( (xLegendProp->getPropertyValue(
"ReferencePageSize") >>= aPropRefSize) &&
126 (aPropRefSize.Height > 0) &&
127 (aTextValueMap[
"CharHeight" ] >>= fFontHeight) )
129 aTextValueMap[
"CharHeight" ] <<=
130 static_cast< float >(
133 if( aTextValueMap[
"CharHeightAsian" ] >>= fFontHeight )
135 aTextValueMap[
"CharHeightAsian" ] <<=
136 static_cast< float >(
139 if( aTextValueMap[
"CharHeightComplex" ] >>= fFontHeight )
141 aTextValueMap[
"CharHeightComplex" ] <<=
142 static_cast< float >(
148 rOutTextProperties.first, rOutTextProperties.second, aTextValueMap );
151awt::Size lcl_createTextShapes(
152 const std::vector<ViewLegendEntry> & rEntries,
155 const tPropertyValues & rTextProperties )
159 for (ViewLegendEntry
const & rEntry : rEntries)
163 OUString aLabelString;
167 if (rEntry.xLabel->getString().getLength() > 520)
169 sal_Int32
nIndex = rEntry.xLabel->getString().indexOf(
' ', 500);
170 rEntry.xLabel->setString(
171 rEntry.xLabel->getString().copy(0, nIndex > 500 ? nIndex : 500));
174 aLabelString += rEntry.xLabel->getString();
176 if( aLabelString.isEmpty())
182 rTextProperties.first, rTextProperties.second,
uno::Any() );
185 awt::Size aCurrSize( xEntry->getSize());
186 aResult.Width = std::max( aResult.Width, aCurrSize.Width );
187 aResult.Height = std::max( aResult.Height, aCurrSize.Height );
189 rOutTextShapes.push_back( xEntry );
191 catch(
const uno::Exception & )
200void lcl_collectColumnWidths( std::vector< sal_Int32 >& rColumnWidths,
const sal_Int32 nNumberOfRows,
const sal_Int32 nNumberOfColumns,
203 rColumnWidths.clear();
204 sal_Int32 nNumberOfEntries = rTextShapes.size();
205 for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow )
207 for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; ++nColumn )
209 sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns;
210 if( nEntry < nNumberOfEntries )
212 awt::Size aTextSize( rTextShapes[ nEntry ]->getSize() );
213 sal_Int32 nWidth = nSymbolPlusDistanceWidth + aTextSize.Width;
215 rColumnWidths.push_back( nWidth );
217 rColumnWidths[nColumn] = std::max( nWidth, rColumnWidths[nColumn] );
223void lcl_collectRowHeighs( std::vector< sal_Int32 >& rRowHeights,
const sal_Int32 nNumberOfRows,
const sal_Int32 nNumberOfColumns,
229 sal_Int32 nNumberOfEntries = rTextShapes.size();
230 for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow)
232 sal_Int32 nCurrentRowHeight = 0;
233 for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; ++nColumn)
235 sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns;
236 if( nEntry < nNumberOfEntries )
238 awt::Size aTextSize( rTextShapes[ nEntry ]->getSize() );
239 nCurrentRowHeight = std::max( nCurrentRowHeight, aTextSize.Height );
242 rRowHeights.push_back( nCurrentRowHeight );
246sal_Int32 lcl_getTextLineHeight(
const std::vector< sal_Int32 >& aRowHeights,
const sal_Int32 nNumberOfRows,
double fViewFontSize )
248 const sal_Int32 nFontHeight =
static_cast< sal_Int32
>( fViewFontSize );
251 sal_Int32 nTextLineHeight = nFontHeight;
252 for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow)
254 sal_Int32 nFullTextHeight = aRowHeights[nRow];
255 if( ( nFullTextHeight / nFontHeight ) <= 1 )
257 nTextLineHeight = nFullTextHeight;
261 return nTextLineHeight;
265awt::Size lcl_placeLegendEntries(
266 std::vector<ViewLegendEntry> & rEntries,
267 css::chart::ChartLegendExpansion eExpansion,
268 bool bSymbolsLeftSide,
269 double fViewFontSize,
270 const awt::Size& rMaxSymbolExtent,
271 tPropertyValues & rTextProperties,
273 const awt::Size& rRemainingSpace,
274 sal_Int32 nYStartPosition,
275 const awt::Size& rPageSize,
277 awt::Size& rDefaultLegendSize)
279 bool bIsCustomSize = (eExpansion == css::chart::ChartLegendExpansion_CUSTOM);
280 awt::Size aResultingLegendSize(0,0);
283 aResultingLegendSize = awt::Size((rPageSize.Width * 13) / 80, (rPageSize.Height * 31) / 90);
285 aResultingLegendSize = awt::Size(rRemainingSpace.Width, rRemainingSpace.Height + nYStartPosition);
288 sal_Int32 nXPadding =
static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize * 0.33 ) );
289 sal_Int32 nXOffset =
static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize * 0.66 ) );
290 sal_Int32 nYPadding =
static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize * 0.2 ) );
291 sal_Int32 nYOffset =
static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize * 0.2 ) );
293 const sal_Int32 nSymbolToTextDistance =
static_cast< sal_Int32
>( std::max( 100.0, fViewFontSize * 0.22 ) );
294 const sal_Int32 nSymbolPlusDistanceWidth = rMaxSymbolExtent.Width + nSymbolToTextDistance;
295 sal_Int32 nMaxTextWidth = rRemainingSpace.Width - nSymbolPlusDistanceWidth;
299 if( eExpansion == css::chart::ChartLegendExpansion_HIGH )
303 nMaxTextWidth = rRemainingSpace.Width * 3 / 10;
305 *pFrameWidthAny <<= nMaxTextWidth;
308 std::vector< rtl::Reference<SvxShapeText> > aTextShapes;
309 awt::Size aMaxEntryExtent = lcl_createTextShapes( rEntries, xTarget, aTextShapes, rTextProperties );
310 OSL_ASSERT( aTextShapes.size() == rEntries.size());
312 sal_Int32 nMaxEntryWidth = nXOffset + nSymbolPlusDistanceWidth + aMaxEntryExtent.Width;
313 sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height;
314 sal_Int32 nNumberOfEntries = rEntries.size();
316 rDefaultLegendSize.Width = nMaxEntryWidth;
317 rDefaultLegendSize.Height = nMaxEntryHeight + nYPadding;
319 sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0;
320 std::vector< sal_Int32 > aColumnWidths;
321 std::vector< sal_Int32 > aRowHeights;
323 sal_Int32 nTextLineHeight =
static_cast< sal_Int32
>( fViewFontSize );
326 if( eExpansion == css::chart::ChartLegendExpansion_CUSTOM )
328 sal_Int32 nCurrentRow=0;
329 sal_Int32 nCurrentColumn=-1;
330 sal_Int32 nMaxColumnCount=-1;
331 for( sal_Int32 nN=0; nN<static_cast<sal_Int32>(aTextShapes.size()); nN++ )
336 awt::Size aSize( xShape->getSize() );
337 sal_Int32 nNewWidth = aSize.Width + nSymbolPlusDistanceWidth;
338 sal_Int32 nCurrentColumnCount = aColumnWidths.size();
341 if( nMaxColumnCount==-1 || (nCurrentColumn+1) < nMaxColumnCount )
345 if( nCurrentColumn < nCurrentColumnCount )
348 if( aColumnWidths[nCurrentColumn]>=nNewWidth )
354 aColumnWidths[nCurrentColumn] = std::max( nNewWidth, aColumnWidths[nCurrentColumn] );
356 aColumnWidths.push_back(nNewWidth);
359 nCurrentColumnCount = aColumnWidths.size();
360 sal_Int32 nSumWidth = 0;
361 for (sal_Int32 nColumn = 0; nColumn < nCurrentColumnCount; nColumn++)
362 nSumWidth += aColumnWidths[nColumn];
364 if( nSumWidth <= rRemainingSpace.Width || nCurrentColumnCount==1 )
373 nMaxColumnCount = nCurrentColumnCount-1;
377 aColumnWidths.clear();
388 nNumberOfColumns = aColumnWidths.size();
389 nNumberOfRows = nCurrentRow+1;
392 lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes );
393 nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize );
394 sal_Int32 nSumHeight = 0;
395 for (sal_Int32 nRow=0; nRow < nNumberOfRows; nRow++)
396 nSumHeight += aRowHeights[nRow];
397 sal_Int32 nRemainingSpace = rRemainingSpace.Height - nSumHeight;
399 if( nRemainingSpace < -100 )
402 for (sal_Int32 nRow = nNumberOfRows; nRow--; )
404 for (sal_Int32 nColumn = nNumberOfColumns; nColumn--; )
406 sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns;
407 if( nEntry <
static_cast<sal_Int32
>(aTextShapes.size()) )
410 aTextShapes.pop_back();
412 if( nEntry < nNumberOfEntries && ( nEntry != 0 || nNumberOfColumns != 1 ) )
419 if (nRow == 0 && nNumberOfColumns == 1)
423 OUString aLabelString = rEntries[0].xLabel->getString();
424 static constexpr OUStringLiteral sDots =
u"...";
425 for (sal_Int32 nNewLen = aLabelString.getLength() - sDots.getLength(); nNewLen > 0; )
427 OUString aNewLabel = aLabelString.subView(0, nNewLen) + sDots;
429 xTarget, aNewLabel, rTextProperties.first, rTextProperties.second,
uno::Any());
430 nSumHeight = xEntry->getSize().Height;
431 nRemainingSpace = rRemainingSpace.Height - nSumHeight;
432 if (nRemainingSpace >= 0)
434 sal_Int32 nWidth = xEntry->getSize().Width + nSymbolPlusDistanceWidth;
435 if (rRemainingSpace.Width - nWidth >= 0)
437 aTextShapes.push_back(xEntry);
438 rEntries[0].xLabel->setString(aNewLabel);
439 aRowHeights[0] = nSumHeight;
440 aColumnWidths[0] = nWidth;
447 if (nNewLen > 10 && std::abs(nRemainingSpace) > nSumHeight / 10)
448 nNewLen -= nNewLen / 10;
452 if (aTextShapes.size() == 0)
457 aRowHeights.pop_back();
460 catch (
const uno::Exception&)
467 nSumHeight -= aRowHeights[nRow];
468 aRowHeights.pop_back();
469 nRemainingSpace = rRemainingSpace.Height - nSumHeight;
470 if (nRemainingSpace >= 0)
474 nNumberOfRows =
static_cast<sal_Int32
>(aRowHeights.size());
476 if( nRemainingSpace >= -100 )
478 sal_Int32 nNormalSpacingHeight = 2*nYPadding+(nNumberOfRows-1)*nYOffset;
479 if( nRemainingSpace < nNormalSpacingHeight )
482 nYPadding = nYOffset = nRemainingSpace/(nNumberOfRows+1);
487 sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingHeight)/(nNumberOfRows+1);
488 nYPadding += nRemainingSingleSpace;
489 nYOffset += nRemainingSingleSpace;
494 sal_Int32 nSumWidth = 0;
495 for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; nColumn++)
496 nSumWidth += aColumnWidths[nColumn];
497 nRemainingSpace = rRemainingSpace.Width - nSumWidth;
498 if( nRemainingSpace>=0 )
500 sal_Int32 nNormalSpacingWidth = 2*nXPadding+(nNumberOfColumns-1)*nXOffset;
501 if( nRemainingSpace < nNormalSpacingWidth )
504 nXPadding = nXOffset = nRemainingSpace/(nNumberOfColumns+1);
509 sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingWidth)/(nNumberOfColumns+1);
510 nXPadding += nRemainingSingleSpace;
511 nXOffset += nRemainingSingleSpace;
515 else if( eExpansion == css::chart::ChartLegendExpansion_HIGH )
517 sal_Int32 nMaxNumberOfRows = nMaxEntryHeight
518 ? (rRemainingSpace.Height - 2*nYPadding ) / nMaxEntryHeight
521 nNumberOfColumns = nMaxNumberOfRows
522 ?
static_cast< sal_Int32
>(
523 ceil(
static_cast< double >( nNumberOfEntries ) /
524 static_cast< double >( nMaxNumberOfRows ) ))
526 nNumberOfRows = nNumberOfColumns
527 ?
static_cast< sal_Int32
>(
528 ceil(
static_cast< double >( nNumberOfEntries ) /
529 static_cast< double >( nNumberOfColumns ) ))
532 else if( eExpansion == css::chart::ChartLegendExpansion_WIDE )
534 sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth
535 ? (rRemainingSpace.Width - 2*nXPadding ) / nMaxEntryWidth
538 nNumberOfRows = nMaxNumberOfColumns
539 ?
static_cast< sal_Int32
>(
540 ceil(
static_cast< double >( nNumberOfEntries ) /
541 static_cast< double >( nMaxNumberOfColumns ) ))
543 nNumberOfColumns = nNumberOfRows
544 ?
static_cast< sal_Int32
>(
545 ceil(
static_cast< double >( nNumberOfEntries ) /
546 static_cast< double >( nNumberOfRows ) ))
551 double fAspect = nMaxEntryHeight
552 ?
static_cast< double >( nMaxEntryWidth ) /
static_cast< double >( nMaxEntryHeight )
555 nNumberOfRows =
static_cast< sal_Int32
>(
556 ceil( sqrt(
static_cast< double >( nNumberOfEntries ) * fAspect )));
557 nNumberOfColumns = nNumberOfRows
558 ?
static_cast< sal_Int32
>(
559 ceil(
static_cast< double >( nNumberOfEntries ) /
560 static_cast< double >( nNumberOfRows ) ))
565 return aResultingLegendSize;
567 if( eExpansion != css::chart::ChartLegendExpansion_CUSTOM )
569 lcl_collectColumnWidths( aColumnWidths, nNumberOfRows, nNumberOfColumns, aTextShapes, nSymbolPlusDistanceWidth );
570 lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes );
571 nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize );
574 sal_Int32 nCurrentXPos = bSymbolsLeftSide ? nXPadding : -nXPadding;
577 sal_Int32 nMaxYPos = 0;
579 for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; ++nColumn)
581 sal_Int32 nCurrentYPos = nYPadding + nYStartPosition;
582 for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow)
584 sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns;
585 if( nEntry >= nNumberOfEntries )
590 if( xTextShape.is() )
592 awt::Size aTextSize( xTextShape->getSize() );
593 sal_Int32 nTextXPos = nCurrentXPos + nSymbolPlusDistanceWidth;
594 if( !bSymbolsLeftSide )
595 nTextXPos = nCurrentXPos - nSymbolPlusDistanceWidth - aTextSize.Width;
596 xTextShape->setPosition( awt::Point( nTextXPos, nCurrentYPos ));
603 awt::Size aSymbolSize( rMaxSymbolExtent );
604 sal_Int32 nSymbolXPos = nCurrentXPos;
605 if( !bSymbolsLeftSide )
606 nSymbolXPos = nCurrentXPos - rMaxSymbolExtent.Width;
607 sal_Int32 nSymbolYPos = nCurrentYPos + ( ( nTextLineHeight - aSymbolSize.Height ) / 2 );
608 xSymbol->setPosition( awt::Point( nSymbolXPos, nSymbolYPos ) );
611 nCurrentYPos += aRowHeights[ nRow ];
612 if( nRow+1 < nNumberOfRows )
613 nCurrentYPos += nYOffset;
614 nMaxYPos = std::max( nMaxYPos, nCurrentYPos );
616 if( bSymbolsLeftSide )
618 nCurrentXPos += aColumnWidths[nColumn];
619 if( nColumn+1 < nNumberOfColumns )
620 nCurrentXPos += nXOffset;
624 nCurrentXPos -= aColumnWidths[nColumn];
625 if( nColumn+1 < nNumberOfColumns )
626 nCurrentXPos -= nXOffset;
632 if( bSymbolsLeftSide )
633 aResultingLegendSize.Width = std::max( aResultingLegendSize.Width, nCurrentXPos + nXPadding );
636 sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding);
637 aResultingLegendSize.Width = std::max( aResultingLegendSize.Width, nLegendWidth );
639 aResultingLegendSize.Height = std::max( aResultingLegendSize.Height, nMaxYPos + nYPadding );
642 if( !bSymbolsLeftSide )
644 sal_Int32 nLegendWidth = aResultingLegendSize.Width;
645 awt::Point aPos(0,0);
646 for( sal_Int32 nEntry=0; nEntry<nNumberOfEntries; nEntry++ )
649 aPos = xSymbol->getPosition();
650 aPos.X += nLegendWidth;
651 xSymbol->setPosition( aPos );
653 aPos = xText->getPosition();
654 aPos.X += nLegendWidth;
655 xText->setPosition( aPos );
659 return aResultingLegendSize;
663sal_Int32 lcl_getLegendLeftRightMargin()
669sal_Int32 lcl_getLegendTopBottomMargin()
674chart2::RelativePosition lcl_getDefaultPosition( LegendPosition
ePos,
const awt::Rectangle& rOutAvailableSpace,
const awt::Size & rPageSize )
676 chart2::RelativePosition aResult;
680 case LegendPosition_LINE_START:
683 const double fDefaultDistance =
static_cast< double >( lcl_getLegendLeftRightMargin() ) /
684 static_cast< double >( rPageSize.Width );
685 aResult = chart2::RelativePosition(
686 fDefaultDistance, 0.5, drawing::Alignment_LEFT );
689 case LegendPosition_LINE_END:
692 const double fDefaultDistance =
static_cast< double >( lcl_getLegendLeftRightMargin() ) /
693 static_cast< double >( rPageSize.Width );
694 aResult = chart2::RelativePosition(
695 1.0 - fDefaultDistance, 0.5, drawing::Alignment_RIGHT );
698 case LegendPosition_PAGE_START:
701 const double fDefaultDistance =
static_cast< double >( lcl_getLegendTopBottomMargin() ) /
702 static_cast< double >( rPageSize.Height );
703 double fDistance = (
static_cast<double>(rOutAvailableSpace.Y)/
static_cast<double>(rPageSize.Height)) + fDefaultDistance;
704 aResult = chart2::RelativePosition(
705 0.5, fDistance, drawing::Alignment_TOP );
708 case LegendPosition_PAGE_END:
711 const double fDefaultDistance =
static_cast< double >( lcl_getLegendTopBottomMargin() ) /
712 static_cast< double >( rPageSize.Height );
714 double fDistance = double(rPageSize.Height - (rOutAvailableSpace.Y + rOutAvailableSpace.Height));
715 fDistance += fDefaultDistance;
716 fDistance /= double(rPageSize.Height);
718 aResult = chart2::RelativePosition(
719 0.5, 1.0 - fDistance, drawing::Alignment_BOTTOM );
722 case LegendPosition::LegendPosition_MAKE_FIXED_SIZE:
735awt::Point lcl_calculatePositionAndRemainingSpace(
736 awt::Rectangle & rRemainingSpace,
737 const awt::Size & rPageSize,
738 const chart2::RelativePosition& rRelPos,
740 const awt::Size& aLegendSize,
745 static_cast< sal_Int32
>( rRelPos.Primary * rPageSize.Width ),
746 static_cast< sal_Int32
>( rRelPos.Secondary * rPageSize.Height ));
749 aResult, aLegendSize, rRelPos.Anchor );
753 sal_Int32 nXDistance = lcl_getLegendLeftRightMargin();
754 sal_Int32 nYDistance = lcl_getLegendTopBottomMargin();
755 if (!bOverlay)
switch(
ePos )
757 case LegendPosition_LINE_START:
759 sal_Int32 nExtent = aLegendSize.Width;
760 rRemainingSpace.Width -= ( nExtent + nXDistance );
761 rRemainingSpace.X += ( nExtent + nXDistance );
764 case LegendPosition_LINE_END:
766 rRemainingSpace.Width -= ( aLegendSize.Width + nXDistance );
769 case LegendPosition_PAGE_START:
771 sal_Int32 nExtent = aLegendSize.Height;
772 rRemainingSpace.Height -= ( nExtent + nYDistance );
773 rRemainingSpace.Y += ( nExtent + nYDistance );
776 case LegendPosition_PAGE_END:
778 rRemainingSpace.Height -= ( aLegendSize.Height + nYDistance );
788 const sal_Int32 nEdgeDistance( 30 );
789 if( aResult.X + aLegendSize.Width > rPageSize.Width )
791 sal_Int32 nNewX( (rPageSize.Width - aLegendSize.Width) - nEdgeDistance );
792 if( nNewX > rPageSize.Width / 4 )
795 if( aResult.Y + aLegendSize.Height > rPageSize.Height )
797 sal_Int32 nNewY( (rPageSize.Height - aLegendSize.Height) - nEdgeDistance );
798 if( nNewY > rPageSize.Height / 4 )
805bool lcl_shouldSymbolsBePlacedOnTheLeftSide(
const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode )
807 bool bSymbolsLeftSide =
true;
814 sal_Int16 nWritingMode=-1;
815 if( xLegendProp->getPropertyValue(
"WritingMode" ) >>= nWritingMode )
817 if( nWritingMode == text::WritingMode2::PAGE )
818 nWritingMode = nDefaultWritingMode;
819 if( nWritingMode == text::WritingMode2::RL_TB )
820 bSymbolsLeftSide=
false;
825 catch(
const uno::Exception & )
829 return bSymbolsLeftSide;
832std::vector<std::shared_ptr<VButton>> lcl_createButtons(
834 ChartModel& rModel,
bool bPlaceButtonsVertically,
tools::Long & nUsedHeight)
836 std::vector<std::shared_ptr<VButton>> aButtons;
838 uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY);
839 if (!xPivotTableDataProvider.is())
842 if (!xPivotTableDataProvider->getColumnFields().hasElements())
845 awt::Size aSize(2000, 700);
849 const css::uno::Sequence<chart2::data::PivotTableFieldEntry> aPivotFieldEntries = xPivotTableDataProvider->getColumnFields();
850 for (chart2::data::PivotTableFieldEntry
const & sColumnFieldEntry : aPivotFieldEntries)
852 auto pButton = std::make_shared<VButton>();
853 aButtons.push_back(pButton);
854 pButton->init(xLegendContainer);
855 awt::Point aNewPosition(x, y);
856 pButton->setLabel(sColumnFieldEntry.Name);
857 pButton->setCID(
"FieldButton.Column." + OUString::number(sColumnFieldEntry.DimensionIndex));
858 pButton->setPosition(aNewPosition);
859 pButton->setSize(aSize);
860 if (sColumnFieldEntry.Name ==
"Data")
862 pButton->showArrow(
false);
863 pButton->setBGColor(
Color(0x00F6F6F6));
865 if (sColumnFieldEntry.HasHiddenMembers)
866 pButton->setArrowColor(
Color(0x0000FF));
868 if (bPlaceButtonsVertically)
869 y += aSize.Height + 100;
871 x += aSize.Width + 100;
873 if (bPlaceButtonsVertically)
874 nUsedHeight +=
y + 100;
876 nUsedHeight += aSize.Height + 100;
886 std::vector< LegendEntryProvider* >&& rLegendEntryProviderList,
890 , m_xLegend(
std::move(xLegend))
893 , m_aLegendEntryProviderList(
std::move(rLegendEntryProviderList))
894 , m_nDefaultWritingMode(
text::WritingMode2::LR_TB)
911 xLegend->getPropertyValue(
"Show") >>= bShow;
913 catch(
const uno::Exception & )
922 const awt::Size & rAvailableSpace,
923 const awt::Size & rPageSize,
924 awt::Size & rDefaultLegendSize )
938 if( xLegendContainer.is() )
941 tPropertyValues aLineFillProperties;
942 tPropertyValues aTextProperties;
944 css::chart::ChartLegendExpansion eExpansion = css::chart::ChartLegendExpansion_HIGH;
945 awt::Size aLegendSize( rAvailableSpace );
947 bool bCustom =
false;
948 LegendPosition eLegendPosition = LegendPosition_LINE_END;
950 m_xLegend->getPropertyValue(
"Expansion") >>= eExpansion;
951 if( eExpansion == css::chart::ChartLegendExpansion_CUSTOM )
954 if (
m_xLegend->getPropertyValue(
"RelativeSize") >>= aRelativeSize)
956 aLegendSize.Width =
static_cast<sal_Int32
>(::rtl::math::approxCeil( aRelativeSize.Primary * rPageSize.Width ));
957 aLegendSize.Height =
static_cast<sal_Int32
>(::rtl::math::approxCeil( aRelativeSize.Secondary * rPageSize.Height ));
962 eExpansion = css::chart::ChartLegendExpansion_HIGH;
965 m_xLegend->getPropertyValue(
"AnchorPosition") >>= eLegendPosition;
966 lcl_getProperties(
m_xLegend, aLineFillProperties, aTextProperties, rPageSize );
969 double fViewFontSize = lcl_CalcViewFontSize(
m_xLegend, rPageSize );
971 sal_Int32 nSymbolHeight =
static_cast< sal_Int32
>( fViewFontSize * 0.6 );
972 sal_Int32 nSymbolWidth = nSymbolHeight;
976 if (pLegendEntryProvider)
978 awt::Size aCurrentRatio = pLegendEntryProvider->getPreferredLegendKeyAspectRatio();
979 sal_Int32 nCurrentWidth = aCurrentRatio.Width;
980 if( aCurrentRatio.Height > 0 )
982 nCurrentWidth = nSymbolHeight* aCurrentRatio.Width/aCurrentRatio.Height;
984 nSymbolWidth = std::max( nSymbolWidth, nCurrentWidth );
987 awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeight );
989 std::vector<ViewLegendEntry> aViewEntries;
992 if (pLegendEntryProvider)
994 std::vector<ViewLegendEntry> aNewEntries = pLegendEntryProvider->createLegendEntries(
995 aMaxSymbolExtent, eLegendPosition,
m_xLegend,
997 aViewEntries.insert( aViewEntries.end(), aNewEntries.begin(), aNewEntries.end() );
1004 bool bIsPivotChart = xPivotTableDataProvider.is();
1006 if ( !aViewEntries.empty() || bIsPivotChart )
1010 bool bPlaceButtonsVertically = (eLegendPosition != LegendPosition_PAGE_START &&
1011 eLegendPosition != LegendPosition_PAGE_END &&
1012 eExpansion != css::chart::ChartLegendExpansion_WIDE);
1014 std::vector<std::shared_ptr<VButton>> aButtons = lcl_createButtons(xLegendContainer,
mrModel, bPlaceButtonsVertically, nUsedButtonHeight);
1019 aLegendSize.Height -= nUsedButtonHeight;
1022 aLegendSize = lcl_placeLegendEntries(aViewEntries, eExpansion, bSymbolsLeftSide, fViewFontSize,
1023 aMaxSymbolExtent, aTextProperties, xLegendContainer,
1024 aLegendSize, nUsedButtonHeight, rPageSize, bIsPivotChart, rDefaultLegendSize);
1028 for (std::shared_ptr<VButton>
const & pButton : aButtons)
1031 if (bPlaceButtonsVertically)
1032 pButton->setSize({aLegendSize.Width - 200, pButton->getSize().
Height});
1035 pButton->createShapes(xModelPage);
1039 xLegendContainer, aLegendSize, awt::Point(0, 0), aLineFillProperties.first,
1047 catch(
const uno::Exception & )
1054 awt::Rectangle & rOutAvailableSpace,
1055 const awt::Size & rPageSize,
1056 const css::awt::Size & rDefaultLegendSize )
1064 awt::Size aLegendSize =
m_xShape->getSize();
1065 chart2::RelativePosition aRelativePosition;
1067 bool bDefaultLegendSize = rDefaultLegendSize.Width != 0 || rDefaultLegendSize.Height != 0;
1068 bool bAutoPosition =
1069 ! (
m_xLegend->getPropertyValue(
"RelativePosition") >>= aRelativePosition);
1071 LegendPosition
ePos = LegendPosition_LINE_END;
1074 bool bOverlay =
false;
1075 m_xLegend->getPropertyValue(
"Overlay") >>= bOverlay;
1080 aRelativePosition = lcl_getDefaultPosition(
ePos, rOutAvailableSpace, rPageSize );
1081 awt::Point aPos = lcl_calculatePositionAndRemainingSpace(
1082 rOutAvailableSpace, rPageSize, aRelativePosition,
ePos, aLegendSize, bOverlay );
1088 awt::Rectangle aAvailableSpace( 0, 0, rPageSize.Width, rPageSize.Height );
1089 awt::Point aPos = lcl_calculatePositionAndRemainingSpace(
1090 aAvailableSpace, rPageSize, aRelativePosition,
ePos, bDefaultLegendSize ? rDefaultLegendSize : aLegendSize, bOverlay );
1096 aRelativePosition = lcl_getDefaultPosition(
ePos, rOutAvailableSpace, rPageSize );
1097 lcl_calculatePositionAndRemainingSpace(
1098 rOutAvailableSpace, rPageSize, aRelativePosition,
ePos, bDefaultLegendSize ? rDefaultLegendSize : aLegendSize, bOverlay );
1102 catch(
const uno::Exception & )
css::chart::ChartAxisLabelPosition ePos
Reference< uno::XComponentContext > m_xContext
constexpr auto convertPointToMm100(N n)
static bool IsCTLFontEnabled()
static bool removeShape(const rtl::Reference< SvxShape > &xShape)
static OUString createClassifiedIdentifierForParticle(std::u16string_view rParticle)
static OUString createParticleForLegend(const rtl::Reference<::chart::ChartModel > &xChartModel)
static const tPropertyNameMap & getPropertyNameMapForFillAndLineProperties()
static css::uno::Any * getValuePointer(tAnySequence &rPropValues, const tNameSequence &rPropNames, std::u16string_view rPropName)
static const tPropertyNameMap & getPropertyNameMapForCharacterProperties()
static void getMultiPropertyListsFromValueMap(tNameSequence &rNames, tAnySequence &rValues, const tPropertyNameValueMap &rValueMap)
static void getValueMap(tPropertyNameValueMap &rValueMap, const tPropertyNameMap &rNameMap, const css::uno::Reference< css::beans::XPropertySet > &xSourceProp)
Fetch property values from the source object and map it to the destination container.
static css::awt::Point getUpperLeftCornerOfAnchoredObject(css::awt::Point aPoint, css::awt::Size aObjectSize, css::drawing::Alignment aAnchor)
returns the upper left corner of an object that has size aObjectSize and where the point indicated by...
static double calculate(double fValue, const css::awt::Size &rOldReferenceSize, const css::awt::Size &rNewReferenceSize)
static void setShapeName(const rtl::Reference< SvxShape > &xShape, const OUString &rName)
static rtl::Reference< SvxShapeRect > createRectangle(const rtl::Reference< SvxShapeGroupAnyD > &xTarget, const css::awt::Size &rSize, const css::awt::Point &rPosition, const tNameSequence &rPropNames, const tAnySequence &rPropValues, StackPosition ePos=StackPosition::Top)
static rtl::Reference< SvxShapeText > createText(const rtl::Reference< SvxShapeGroupAnyD > &xTarget2D, const OUString &rText, const tNameSequence &rPropNames, const tAnySequence &rPropValues, const css::uno::Any &rATransformation)
static rtl::Reference< SvxShapeGroup > createGroup2D(const rtl::Reference< SvxShapeGroupAnyD > &xTarget, const OUString &aName=OUString())
void setDefaultWritingMode(sal_Int16 nDefaultWritingMode)
css::uno::Reference< css::uno::XComponentContext > m_xContext
rtl::Reference<::chart::Legend > m_xLegend
void createShapes(const css::awt::Size &rAvailableSpace, const css::awt::Size &rPageSize, css::awt::Size &rDefaultLegendSize)
std::vector< LegendEntryProvider * > m_aLegendEntryProviderList
VLegend(rtl::Reference< ::chart::Legend > xLegend, const css::uno::Reference< css::uno::XComponentContext > &xContext, std::vector< LegendEntryProvider * > &&rLegendEntryProviderList, rtl::Reference< SvxShapeGroupAnyD > xTargetPage, ChartModel &rModel)
sal_Int16 m_nDefaultWritingMode
rtl::Reference< SvxShapeGroup > m_xShape
static bool isVisible(const rtl::Reference< ::chart::Legend > &xLegend)
rtl::Reference< SvxShapeGroupAnyD > m_xTarget
void changePosition(css::awt::Rectangle &rOutAvailableSpace, const css::awt::Size &rReferenceSize, const css::awt::Size &rDefaultLegendSize)
Sets the position according to its internal anchor.
Reference< lang::XComponent > m_xTarget
#define DBG_UNHANDLED_EXCEPTION(...)
std::unordered_map< OUString, css::uno::Any > tPropertyNameValueMap