Avoid potential negative array index access to cached text.
[LibreOffice.git] / chart2 / source / tools / TitleHelper.cxx
blob992f5cdf61969757073c0327f2fdb83160f78f6f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <TitleHelper.hxx>
21 #include <Title.hxx>
22 #include <ChartModel.hxx>
23 #include <ChartModelHelper.hxx>
24 #include <Axis.hxx>
25 #include <AxisHelper.hxx>
26 #include <DiagramHelper.hxx>
27 #include <Diagram.hxx>
28 #include <ReferenceSizeProvider.hxx>
29 #include <com/sun/star/chart2/FormattedString.hpp>
30 #include <rtl/ustrbuf.hxx>
31 #include <comphelper/diagnose_ex.hxx>
32 #include <sal/log.hxx>
34 namespace chart
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::chart2;
39 using ::com::sun::star::uno::Reference;
41 namespace {
43 uno::Reference< XTitled > lcl_getTitleParentFromDiagram(
44 TitleHelper::eTitleType nTitleIndex
45 , const rtl::Reference< Diagram >& xDiagram )
47 uno::Reference< XTitled > xResult;
49 if( nTitleIndex == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ||
50 nTitleIndex == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
52 bool bDummy = false;
53 bool bIsVertical = xDiagram && xDiagram->getVertical( bDummy, bDummy );
55 if( nTitleIndex == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
56 nTitleIndex = bIsVertical ? TitleHelper::X_AXIS_TITLE : TitleHelper::Y_AXIS_TITLE;
57 else
58 nTitleIndex = bIsVertical ? TitleHelper::Y_AXIS_TITLE : TitleHelper::X_AXIS_TITLE;
61 switch( nTitleIndex )
63 case TitleHelper::SUB_TITLE:
64 if( xDiagram.is())
65 xResult = xDiagram;
66 break;
67 case TitleHelper::X_AXIS_TITLE:
68 if( xDiagram.is())
69 xResult = AxisHelper::getAxis( 0, true, xDiagram );
70 break;
71 case TitleHelper::Y_AXIS_TITLE:
72 if( xDiagram.is())
73 xResult = AxisHelper::getAxis( 1, true, xDiagram );
74 break;
75 case TitleHelper::Z_AXIS_TITLE:
76 if( xDiagram.is())
77 xResult = AxisHelper::getAxis( 2, true, xDiagram );
78 break;
79 case TitleHelper::SECONDARY_X_AXIS_TITLE:
80 if( xDiagram.is())
81 xResult = AxisHelper::getAxis( 0, false, xDiagram );
82 break;
83 case TitleHelper::SECONDARY_Y_AXIS_TITLE:
84 if( xDiagram.is())
85 xResult = AxisHelper::getAxis( 1, false, xDiagram );
86 break;
88 case TitleHelper::MAIN_TITLE:
89 default:
90 OSL_FAIL( "Unsupported Title-Type requested" );
91 break;
94 return xResult;
97 uno::Reference< XTitled > lcl_getTitleParent( TitleHelper::eTitleType nTitleIndex
98 , const rtl::Reference< Diagram >& xDiagram )
100 uno::Reference< XTitled > xResult;
101 switch( nTitleIndex )
103 case TitleHelper::MAIN_TITLE:
104 SAL_WARN("chart2", "should not be reached");
105 break;
106 case TitleHelper::SUB_TITLE:
107 case TitleHelper::X_AXIS_TITLE:
108 case TitleHelper::Y_AXIS_TITLE:
109 case TitleHelper::Z_AXIS_TITLE:
110 case TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION:
111 case TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION:
112 case TitleHelper::SECONDARY_X_AXIS_TITLE:
113 case TitleHelper::SECONDARY_Y_AXIS_TITLE:
114 xResult.set( lcl_getTitleParentFromDiagram( nTitleIndex, xDiagram ));
115 break;
116 default:
117 OSL_FAIL( "Unsupported Title-Type requested" );
118 break;
121 return xResult;
124 uno::Reference< XTitled > lcl_getTitleParent( TitleHelper::eTitleType nTitleIndex
125 , const rtl::Reference<::chart::ChartModel>& xModel )
127 if(nTitleIndex == TitleHelper::MAIN_TITLE)
129 return xModel;
132 rtl::Reference< Diagram > xDiagram;
134 if( xModel.is())
135 xDiagram = xModel->getFirstChartDiagram();
137 return lcl_getTitleParent( nTitleIndex, xDiagram );
142 rtl::Reference< Title > TitleHelper::getTitle( TitleHelper::eTitleType nTitleIndex
143 , ChartModel& rModel )
145 if(nTitleIndex == TitleHelper::MAIN_TITLE)
146 return rModel.getTitleObject2();
148 rtl::Reference< Diagram > xDiagram = rModel.getFirstChartDiagram();
149 uno::Reference< XTitled > xTitled( lcl_getTitleParent( nTitleIndex, xDiagram ) );
150 if( !xTitled )
151 return nullptr;
152 uno::Reference<XTitle> xTitle = xTitled->getTitleObject();
153 auto pTitle = dynamic_cast<Title*>(xTitle.get());
154 assert(!xTitle || pTitle);
155 return pTitle;
158 rtl::Reference< Title > TitleHelper::getTitle( TitleHelper::eTitleType nTitleIndex
159 , const rtl::Reference<ChartModel>& xModel )
161 uno::Reference< XTitled > xTitled;
162 if(nTitleIndex == TitleHelper::MAIN_TITLE)
164 xTitled = xModel;
166 else
168 rtl::Reference< Diagram > xDiagram;
169 if( xModel.is())
170 xDiagram = xModel->getFirstChartDiagram();
171 xTitled = lcl_getTitleParent( nTitleIndex, xDiagram );
173 if( !xTitled )
174 return nullptr;
175 uno::Reference<XTitle> xTitle = xTitled->getTitleObject();
176 Title* pTitle = dynamic_cast<Title*>(xTitle.get());
177 assert(!xTitle || pTitle);
178 return pTitle;
181 rtl::Reference< Title > TitleHelper::createOrShowTitle(
182 TitleHelper::eTitleType eTitleType
183 , const OUString& rTitleText
184 , const rtl::Reference<ChartModel>& xModel
185 , const uno::Reference< uno::XComponentContext > & xContext )
187 rtl::Reference< Title > xTitled( TitleHelper::getTitle( eTitleType, xModel ) );
188 if( xTitled.is())
190 xTitled->setPropertyValue("Visible",css::uno::Any(true));
191 return xTitled;
193 else
195 return createTitle(eTitleType, rTitleText, xModel, xContext, nullptr/*pRefSizeProvider*/);
199 rtl::Reference< Title > TitleHelper::createTitle(
200 TitleHelper::eTitleType eTitleType
201 , const OUString& rTitleText
202 , const rtl::Reference<ChartModel>& xModel
203 , const uno::Reference< uno::XComponentContext > & xContext
204 , ReferenceSizeProvider * pRefSizeProvider )
206 rtl::Reference< ::chart::Title > xTitle;
207 uno::Reference< XTitled > xTitled( lcl_getTitleParent( eTitleType, xModel ) );
209 if( !xTitled.is() )
211 rtl::Reference< Diagram > xDiagram( xModel->getFirstChartDiagram() );
212 rtl::Reference< Axis > xAxis;
213 switch( eTitleType )
215 case TitleHelper::SECONDARY_X_AXIS_TITLE:
216 xAxis = AxisHelper::createAxis( 0, false, xDiagram, xContext );
217 break;
218 case TitleHelper::SECONDARY_Y_AXIS_TITLE:
219 xAxis = AxisHelper::createAxis( 1, false, xDiagram, xContext );
220 break;
221 default:
222 break;
224 if( xAxis.is() )
226 xAxis->setPropertyValue( "Show", uno::Any( false ) );
227 xTitled = lcl_getTitleParent( eTitleType, xModel );
231 if(xTitled.is())
233 rtl::Reference< Diagram > xDiagram( xModel->getFirstChartDiagram() );
235 xTitle = new ::chart::Title();
237 // default char height (main: 13.0 == default)
238 float fDefaultCharHeightSub = 11.0;
239 float fDefaultCharHeightAxis = 9.0;
240 switch( eTitleType )
242 case TitleHelper::SUB_TITLE:
243 TitleHelper::setCompleteString(
244 rTitleText, xTitle, xContext, & fDefaultCharHeightSub );
245 break;
246 case TitleHelper::X_AXIS_TITLE:
247 case TitleHelper::Y_AXIS_TITLE:
248 case TitleHelper::Z_AXIS_TITLE:
249 case TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION:
250 case TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION:
251 case TitleHelper::SECONDARY_X_AXIS_TITLE:
252 case TitleHelper::SECONDARY_Y_AXIS_TITLE:
253 TitleHelper::setCompleteString(
254 rTitleText, xTitle, xContext, & fDefaultCharHeightAxis );
255 break;
256 default:
257 TitleHelper::setCompleteString( rTitleText, xTitle, xContext );
258 break;
261 // set/clear autoscale
262 if( pRefSizeProvider )
263 pRefSizeProvider->setValuesAtTitle( xTitle );
265 xTitled->setTitleObject( xTitle );
267 //default rotation 90 degree for y axis title in normal coordinatesystems or for x axis title for swapped coordinatesystems
268 if( eTitleType == TitleHelper::X_AXIS_TITLE ||
269 eTitleType == TitleHelper::Y_AXIS_TITLE ||
270 eTitleType == TitleHelper::SECONDARY_X_AXIS_TITLE ||
271 eTitleType == TitleHelper::SECONDARY_Y_AXIS_TITLE )
276 bool bDummy = false;
277 bool bIsVertical = xDiagram->getVertical( bDummy, bDummy );
279 if( (!bIsVertical && eTitleType == TitleHelper::Y_AXIS_TITLE)
280 || (bIsVertical && eTitleType == TitleHelper::X_AXIS_TITLE)
281 || (!bIsVertical && eTitleType == TitleHelper::SECONDARY_Y_AXIS_TITLE)
282 || (bIsVertical && eTitleType == TitleHelper::SECONDARY_X_AXIS_TITLE) )
284 xTitle->setPropertyValue( "TextRotation", uno::Any( 90.0 ));
287 catch( const uno::Exception & )
289 DBG_UNHANDLED_EXCEPTION("chart2");
293 return xTitle;
297 OUString TitleHelper::getCompleteString( const rtl::Reference< Title >& xTitle )
299 if(!xTitle.is())
300 return OUString();
301 OUStringBuffer aRet;
302 const uno::Sequence< uno::Reference< XFormattedString > > aStringList = xTitle->getText();
303 for( uno::Reference< XFormattedString > const & formattedStr : aStringList )
304 aRet.append( formattedStr->getString() );
305 return aRet.makeStringAndClear();
308 void TitleHelper::setCompleteString( const OUString& rNewText
309 , const rtl::Reference< Title >& xTitle
310 , const uno::Reference< uno::XComponentContext > & xContext
311 , const float * pDefaultCharHeight /* = 0 */ )
313 //the format of the first old text portion will be maintained if there is any
314 if(!xTitle.is())
315 return;
317 OUString aNewText = rNewText;
319 bool bStacked = false;
320 if( xTitle.is() )
321 xTitle->getPropertyValue( "StackCharacters" ) >>= bStacked;
323 if( bStacked )
325 //#i99841# remove linebreaks that were added for vertical stacking
326 OUStringBuffer aUnstackedStr;
327 OUStringBuffer aSource(rNewText);
329 bool bBreakIgnored = false;
330 sal_Int32 nLen = rNewText.getLength();
331 for( sal_Int32 nPos = 0; nPos < nLen; ++nPos )
333 sal_Unicode aChar = aSource[nPos];
334 if( aChar != '\n' )
336 aUnstackedStr.append( aChar );
337 bBreakIgnored = false;
339 else if( aChar == '\n' && bBreakIgnored )
340 aUnstackedStr.append( aChar );
341 else
342 bBreakIgnored = true;
344 aNewText = aUnstackedStr.makeStringAndClear();
347 uno::Sequence< uno::Reference< XFormattedString > > aNewStringList;
349 uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText();
350 if( aOldStringList.hasElements() )
352 aNewStringList = { aOldStringList[0] };
353 aNewStringList[0]->setString( aNewText );
355 else
357 uno::Reference< chart2::XFormattedString2 > xFormattedString =
358 chart2::FormattedString::create( xContext );
360 xFormattedString->setString( aNewText );
361 aNewStringList = { xFormattedString };
362 if( pDefaultCharHeight != nullptr )
366 uno::Any aFontSize( *pDefaultCharHeight );
367 xFormattedString->setPropertyValue( "CharHeight", aFontSize );
368 xFormattedString->setPropertyValue( "CharHeightAsian", aFontSize );
369 xFormattedString->setPropertyValue( "CharHeightComplex", aFontSize );
371 catch( const uno::Exception & )
373 DBG_UNHANDLED_EXCEPTION("chart2");
377 xTitle->setText( aNewStringList );
380 void TitleHelper::removeTitle( TitleHelper::eTitleType nTitleIndex
381 , const rtl::Reference<ChartModel>& xModel )
383 uno::Reference< XTitled > xTitled( lcl_getTitleParent( nTitleIndex, xModel ) );
384 if( xTitled.is())
386 xTitled->setTitleObject(nullptr);
390 bool TitleHelper::getTitleType( eTitleType& rType
391 , const rtl::Reference< Title >& xTitle
392 , const rtl::Reference<ChartModel>& xModel )
394 if( !xTitle.is() || !xModel.is() )
395 return false;
397 rtl::Reference< Title > xCurrentTitle;
398 for( sal_Int32 nTitleType = TITLE_BEGIN; nTitleType < NORMAL_TITLE_END; nTitleType++ )
400 xCurrentTitle = TitleHelper::getTitle( static_cast<eTitleType>(nTitleType), xModel );
401 if( xCurrentTitle == xTitle )
403 rType = static_cast<eTitleType>(nTitleType);
404 return true;
408 return false;
411 void TitleHelper::hideTitle( TitleHelper::eTitleType nTitleIndex
412 , const rtl::Reference<ChartModel>& xModel)
414 uno::Reference< chart2::XTitle > xTitled( TitleHelper::getTitle( nTitleIndex, xModel ) );
415 if( xTitled.is())
417 css::uno::Reference<css::beans::XPropertySet> xProps(xTitled, css::uno::UNO_QUERY_THROW);
418 xProps->setPropertyValue("Visible",css::uno::Any(false));
422 } //namespace chart
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */