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: */
|