Avoid potential negative array index access to cached text.
[LibreOffice.git] / chart2 / source / tools / AxisHelper.cxx
blobe8e90c5e429f6d0b7d76fb70533f61b0ed13983b
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 <AxisHelper.hxx>
21 #include <DiagramHelper.hxx>
22 #include <Diagram.hxx>
23 #include <ChartTypeHelper.hxx>
24 #include <ChartType.hxx>
25 #include <Axis.hxx>
26 #include <AxisIndexDefines.hxx>
27 #include <DataSource.hxx>
28 #include <LinePropertiesHelper.hxx>
29 #include <servicenames_coosystems.hxx>
30 #include <DataSeries.hxx>
31 #include <DataSeriesHelper.hxx>
32 #include <Scaling.hxx>
33 #include <ChartModel.hxx>
34 #include <ChartModelHelper.hxx>
35 #include <DataSourceHelper.hxx>
36 #include <ReferenceSizeProvider.hxx>
37 #include <ExplicitCategoriesProvider.hxx>
38 #include <unonames.hxx>
39 #include <BaseCoordinateSystem.hxx>
40 #include <GridProperties.hxx>
42 #include <o3tl/safeint.hxx>
43 #include <unotools/saveopt.hxx>
45 #include <com/sun/star/chart/ChartAxisPosition.hpp>
46 #include <com/sun/star/chart2/AxisType.hpp>
48 #include <sal/log.hxx>
50 #include <com/sun/star/lang/XServiceName.hpp>
51 #include <com/sun/star/uno/XComponentContext.hpp>
52 #include <comphelper/sequence.hxx>
53 #include <comphelper/diagnose_ex.hxx>
55 #include <cstddef>
56 #include <map>
58 namespace chart
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::chart2;
62 using ::com::sun::star::uno::Reference;
63 using ::com::sun::star::uno::Sequence;
65 Reference< chart2::XScaling > AxisHelper::createLinearScaling()
67 return new LinearScaling( 1.0, 0.0 );
70 Reference< chart2::XScaling > AxisHelper::createLogarithmicScaling( double fBase )
72 return new LogarithmicScaling( fBase );
75 ScaleData AxisHelper::createDefaultScale()
77 ScaleData aScaleData;
78 aScaleData.AxisType = chart2::AxisType::REALNUMBER;
79 aScaleData.AutoDateAxis = true;
80 aScaleData.ShiftedCategoryPosition = false;
81 Sequence< SubIncrement > aSubIncrements{ SubIncrement() };
82 aScaleData.IncrementData.SubIncrements = aSubIncrements;
83 return aScaleData;
86 void AxisHelper::removeExplicitScaling( ScaleData& rScaleData )
88 uno::Any aEmpty;
89 rScaleData.Minimum = rScaleData.Maximum = rScaleData.Origin = aEmpty;
90 rScaleData.Scaling = nullptr;
91 ScaleData aDefaultScale( createDefaultScale() );
92 rScaleData.IncrementData = aDefaultScale.IncrementData;
93 rScaleData.TimeIncrement = aDefaultScale.TimeIncrement;
96 bool AxisHelper::isLogarithmic( const Reference< XScaling >& xScaling )
98 Reference< lang::XServiceName > xServiceName( xScaling, uno::UNO_QUERY );
99 return xServiceName.is()
100 && xServiceName->getServiceName() == "com.sun.star.chart2.LogarithmicScaling";
103 chart2::ScaleData AxisHelper::getDateCheckedScale( const rtl::Reference< Axis >& xAxis, ChartModel& rModel )
105 ScaleData aScale = xAxis->getScaleData();
106 rtl::Reference< BaseCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( &rModel ) );
107 if( aScale.AutoDateAxis && aScale.AxisType == AxisType::CATEGORY )
109 sal_Int32 nDimensionIndex=0; sal_Int32 nAxisIndex=0;
110 AxisHelper::getIndicesForAxis(xAxis, xCooSys, nDimensionIndex, nAxisIndex );
111 bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionIndex );
112 if( bChartTypeAllowsDateAxis )
113 aScale.AxisType = AxisType::DATE;
115 if( aScale.AxisType == AxisType::DATE )
117 ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel );
118 if( !aExplicitCategoriesProvider.isDateAxis() )
119 aScale.AxisType = AxisType::CATEGORY;
121 return aScale;
124 void AxisHelper::checkDateAxis( chart2::ScaleData& rScale, ExplicitCategoriesProvider* pExplicitCategoriesProvider, bool bChartTypeAllowsDateAxis )
126 if( rScale.AutoDateAxis && rScale.AxisType == AxisType::CATEGORY && bChartTypeAllowsDateAxis )
128 rScale.AxisType = AxisType::DATE;
129 removeExplicitScaling( rScale );
131 if( rScale.AxisType == AxisType::DATE && (!pExplicitCategoriesProvider || !pExplicitCategoriesProvider->isDateAxis()) )
133 rScale.AxisType = AxisType::CATEGORY;
134 removeExplicitScaling( rScale );
138 sal_Int32 AxisHelper::getExplicitNumberFormatKeyForAxis(
139 const rtl::Reference< Axis >& xAxis
140 , const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem
141 , const rtl::Reference<ChartModel>& xChartDoc
142 , bool bSearchForParallelAxisIfNothingIsFound )
144 sal_Int32 nNumberFormatKey(0);
145 sal_Int32 nAxisIndex = 0;
146 sal_Int32 nDimensionIndex = 1;
147 AxisHelper::getIndicesForAxis( xAxis, xCorrespondingCoordinateSystem, nDimensionIndex, nAxisIndex );
149 if (!xAxis.is())
150 return 0;
152 bool bLinkToSource = true;
153 xAxis->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource;
154 xAxis->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey;
156 if (bLinkToSource)
158 bool bFormatSet = false;
159 //check whether we have a percent scale -> use percent format
160 if (xChartDoc)
162 ScaleData aData = AxisHelper::getDateCheckedScale( xAxis, *xChartDoc );
163 if( aData.AxisType==AxisType::PERCENT )
165 sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( xChartDoc );
166 if( nPercentFormat != -1 )
168 nNumberFormatKey = nPercentFormat;
169 bFormatSet = true;
172 else if( aData.AxisType==AxisType::DATE )
174 if( aData.Categories.is() )
176 Reference< data::XDataSequence > xSeq( aData.Categories->getValues());
177 if( xSeq.is() && !( xChartDoc.is() && xChartDoc->hasInternalDataProvider()) )
178 nNumberFormatKey = xSeq->getNumberFormatKeyByIndex( -1 );
179 else
180 nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc );
181 bFormatSet = true;
184 else if( xChartDoc.is() && xChartDoc->hasInternalDataProvider() && nDimensionIndex == 0 ) //maybe date axis
186 rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram() );
187 if( xDiagram->isSupportingDateAxis() )
189 nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc );
191 else
193 rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *xChartDoc );
194 if( xSource.is() )
196 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aXValues(
197 DataSeriesHelper::getAllDataSequencesByRole( xSource->getDataSequences(), "values-x" ) );
198 if( aXValues.empty() )
200 uno::Reference< chart2::data::XLabeledDataSequence > xCategories( xDiagram->getCategories() );
201 if( xCategories.is() )
203 Reference< data::XDataSequence > xSeq( xCategories->getValues());
204 if( xSeq.is() )
206 bool bHasValidDoubles = false;
207 double fTest=0.0;
208 Sequence< uno::Any > aCats( xSeq->getData() );
209 sal_Int32 nCount = aCats.getLength();
210 for( sal_Int32 i = 0; i < nCount; ++i )
212 if( (aCats[i]>>=fTest) && !std::isnan(fTest) )
214 bHasValidDoubles=true;
215 break;
218 if( bHasValidDoubles )
219 nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc );
225 bFormatSet = true;
229 if( !bFormatSet )
231 std::map< sal_Int32, sal_Int32 > aKeyMap;
232 bool bNumberFormatKeyFoundViaAttachedData = false;
236 OUString aRoleToMatch;
237 if( nDimensionIndex == 0 )
238 aRoleToMatch = "values-x";
239 const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCorrespondingCoordinateSystem->getChartTypes2());
240 for( rtl::Reference< ChartType > const & chartType : aChartTypes )
242 if( nDimensionIndex != 0 )
243 aRoleToMatch = ChartTypeHelper::getRoleOfSequenceForYAxisNumberFormatDetection( chartType );
244 for( rtl::Reference< DataSeries > const & xDataSeries : chartType->getDataSeries2() )
246 if( nDimensionIndex == 1 )
248 //only take those series into account that are attached to this axis
249 sal_Int32 nAttachedAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
250 if( nAttachedAxisIndex != nAxisIndex )
251 continue;
254 Reference< data::XLabeledDataSequence > xLabeledSeq(
255 DataSeriesHelper::getDataSequenceByRole( xDataSeries, aRoleToMatch ) );
257 if( !xLabeledSeq.is() && nDimensionIndex==0 )
259 ScaleData aData = xAxis->getScaleData();
260 xLabeledSeq = aData.Categories;
263 if( xLabeledSeq.is() )
265 Reference< data::XDataSequence > xSeq( xLabeledSeq->getValues());
266 if( xSeq.is() )
268 sal_Int32 nKey = xSeq->getNumberFormatKeyByIndex( -1 );
269 // increase frequency
270 aKeyMap[ nKey ] ++;
276 catch( const uno::Exception & )
278 DBG_UNHANDLED_EXCEPTION("chart2");
281 if( ! aKeyMap.empty())
283 sal_Int32 nMaxFreq = 0;
284 // find most frequent key
285 for (auto const& elem : aKeyMap)
287 SAL_INFO(
288 "chart2.tools",
289 "NumberFormatKey " << elem.first << " appears "
290 << elem.second << " times");
291 // all values must at least be 1
292 if( elem.second > nMaxFreq )
294 nNumberFormatKey = elem.first;
295 bNumberFormatKeyFoundViaAttachedData = true;
296 nMaxFreq = elem.second;
301 if( bSearchForParallelAxisIfNothingIsFound )
303 //no format is set to this axis and no data is set to this axis
304 //--> try to obtain the format from the parallel y-axis
305 if( !bNumberFormatKeyFoundViaAttachedData && nDimensionIndex == 1 )
307 sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1;
308 rtl::Reference< Axis > xParallelAxis = AxisHelper::getAxis( 1, nParallelAxisIndex, xCorrespondingCoordinateSystem );
309 nNumberFormatKey = AxisHelper::getExplicitNumberFormatKeyForAxis(xParallelAxis, xCorrespondingCoordinateSystem, xChartDoc, false);
315 return nNumberFormatKey;
318 rtl::Reference< Axis > AxisHelper::createAxis(
319 sal_Int32 nDimensionIndex
320 , sal_Int32 nAxisIndex // 0==main or 1==secondary axis
321 , const rtl::Reference< BaseCoordinateSystem >& xCooSys
322 , const Reference< uno::XComponentContext > & xContext
323 , ReferenceSizeProvider * pRefSizeProvider )
325 if( !xContext.is() || !xCooSys.is() )
326 return nullptr;
327 if( nDimensionIndex >= xCooSys->getDimension() )
328 return nullptr;
330 rtl::Reference< Axis > xAxis = new Axis();
332 xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex );
334 if( nAxisIndex>0 )//when inserting secondary axes copy some things from the main axis
336 css::chart::ChartAxisPosition eNewAxisPos( css::chart::ChartAxisPosition_END );
338 rtl::Reference< Axis > xMainAxis = xCooSys->getAxisByDimension2( nDimensionIndex, 0 );
339 if( xMainAxis.is() )
341 ScaleData aScale = xAxis->getScaleData();
342 ScaleData aMainScale = xMainAxis->getScaleData();
344 aScale.AxisType = aMainScale.AxisType;
345 aScale.AutoDateAxis = aMainScale.AutoDateAxis;
346 aScale.Categories = aMainScale.Categories;
347 aScale.Orientation = aMainScale.Orientation;
348 aScale.ShiftedCategoryPosition = aMainScale.ShiftedCategoryPosition;
350 xAxis->setScaleData( aScale );
352 //ensure that the second axis is not placed on the main axis
353 css::chart::ChartAxisPosition eMainAxisPos( css::chart::ChartAxisPosition_ZERO );
354 xMainAxis->getPropertyValue("CrossoverPosition") >>= eMainAxisPos;
355 if( eMainAxisPos == css::chart::ChartAxisPosition_END )
356 eNewAxisPos = css::chart::ChartAxisPosition_START;
359 xAxis->setPropertyValue("CrossoverPosition", uno::Any(eNewAxisPos) );
364 // set correct initial AutoScale
365 if( pRefSizeProvider )
366 pRefSizeProvider->setValuesAtPropertySet( xAxis );
368 catch( const uno::Exception& )
370 TOOLS_WARN_EXCEPTION("chart2", "" );
372 return xAxis;
375 rtl::Reference< Axis > AxisHelper::createAxis( sal_Int32 nDimensionIndex, bool bMainAxis
376 , const rtl::Reference< Diagram >& xDiagram
377 , const Reference< uno::XComponentContext >& xContext
378 , ReferenceSizeProvider * pRefSizeProvider )
380 OSL_ENSURE( xContext.is(), "need a context to create an axis" );
381 if( !xContext.is() )
382 return nullptr;
384 sal_Int32 nAxisIndex = bMainAxis ? MAIN_AXIS_INDEX : SECONDARY_AXIS_INDEX;
385 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 );
387 // create axis
388 return AxisHelper::createAxis(
389 nDimensionIndex, nAxisIndex, xCooSys, xContext, pRefSizeProvider );
392 void AxisHelper::showAxis( sal_Int32 nDimensionIndex, bool bMainAxis
393 , const rtl::Reference< Diagram >& xDiagram
394 , const Reference< uno::XComponentContext >& xContext
395 , ReferenceSizeProvider * pRefSizeProvider )
397 if( !xDiagram.is() )
398 return;
400 bool bNewAxisCreated = false;
401 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram );
402 if( !xAxis.is() && xContext.is() )
404 // create axis
405 bNewAxisCreated = true;
406 xAxis = AxisHelper::createAxis( nDimensionIndex, bMainAxis, xDiagram, xContext, pRefSizeProvider );
409 OSL_ASSERT( xAxis.is());
410 if( !bNewAxisCreated ) //default is true already if created
411 AxisHelper::makeAxisVisible( xAxis );
414 void AxisHelper::showGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid
415 , const rtl::Reference< Diagram >& xDiagram )
417 if( !xDiagram.is() )
418 return;
420 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex );
421 if(!xCooSys.is())
422 return;
424 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys );
425 if(!xAxis.is())
427 //hhhh todo create axis without axis visibility
429 if(!xAxis.is())
430 return;
432 if( bMainGrid )
433 AxisHelper::makeGridVisible( xAxis->getGridProperties2() );
434 else
436 std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
437 for( auto const & i : aSubGrids )
438 AxisHelper::makeGridVisible( i );
442 void AxisHelper::makeAxisVisible( const rtl::Reference< Axis >& xAxis )
444 if( xAxis.is() )
446 xAxis->setPropertyValue( "Show", uno::Any( true ) );
447 LinePropertiesHelper::SetLineVisible( xAxis );
448 xAxis->setPropertyValue( "DisplayLabels", uno::Any( true ) );
452 void AxisHelper::makeGridVisible( const rtl::Reference< GridProperties >& xGridProperties )
454 if( xGridProperties.is() )
456 xGridProperties->setPropertyValue( "Show", uno::Any( true ) );
457 LinePropertiesHelper::SetLineVisible( xGridProperties );
461 void AxisHelper::hideAxis( sal_Int32 nDimensionIndex, bool bMainAxis
462 , const rtl::Reference< Diagram >& xDiagram )
464 AxisHelper::makeAxisInvisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) );
467 void AxisHelper::makeAxisInvisible( const rtl::Reference< Axis >& xAxis )
469 if( xAxis.is() )
471 xAxis->setPropertyValue( "Show", uno::Any( false ) );
475 void AxisHelper::hideAxisIfNoDataIsAttached( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram )
477 //axis is hidden if no data is attached anymore but data is available
478 bool bOtherSeriesAttachedToThisAxis = false;
479 std::vector< rtl::Reference< DataSeries > > aSeriesVector = xDiagram->getDataSeries();
480 for (auto const& series : aSeriesVector)
482 rtl::Reference< Axis > xCurrentAxis = xDiagram->getAttachedAxis(series);
483 if( xCurrentAxis==xAxis )
485 bOtherSeriesAttachedToThisAxis = true;
486 break;
489 if(!bOtherSeriesAttachedToThisAxis && !aSeriesVector.empty() )
490 AxisHelper::makeAxisInvisible( xAxis );
493 void AxisHelper::hideGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid
494 , const rtl::Reference< Diagram >& xDiagram )
496 if( !xDiagram.is() )
497 return;
499 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex );
500 if(!xCooSys.is())
501 return;
503 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys );
504 if(!xAxis.is())
505 return;
507 if( bMainGrid )
508 AxisHelper::makeGridInvisible( xAxis->getGridProperties2() );
509 else
511 std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
512 for( auto const & i : aSubGrids)
513 AxisHelper::makeGridInvisible( i );
517 void AxisHelper::makeGridInvisible( const rtl::Reference< ::chart::GridProperties >& xGridProperties )
519 if( xGridProperties.is() )
521 xGridProperties->setPropertyValue( "Show", uno::Any( false ) );
525 bool AxisHelper::isGridShown( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid
526 , const rtl::Reference< Diagram >& xDiagram )
528 bool bRet = false;
530 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex );
531 if(!xCooSys.is())
532 return bRet;
534 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys );
535 if(!xAxis.is())
536 return bRet;
538 if( bMainGrid )
539 bRet = AxisHelper::isGridVisible( xAxis->getGridProperties2() );
540 else
542 std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
543 if( !aSubGrids.empty() )
544 bRet = AxisHelper::isGridVisible( aSubGrids[0] );
547 return bRet;
550 rtl::Reference< ::chart::BaseCoordinateSystem > AxisHelper::getCoordinateSystemByIndex(
551 const rtl::Reference< Diagram >& xDiagram, sal_Int32 nIndex )
553 if(!xDiagram.is())
554 return nullptr;
555 auto aCooSysList = xDiagram->getBaseCoordinateSystems();
556 if(0<=nIndex && o3tl::make_unsigned(nIndex) < aCooSysList.size())
557 return aCooSysList[nIndex];
558 return nullptr;
561 rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, bool bMainAxis
562 , const rtl::Reference< Diagram >& xDiagram )
564 rtl::Reference< Axis > xRet;
567 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 );
568 xRet = AxisHelper::getAxis( nDimensionIndex, bMainAxis ? 0 : 1, xCooSys );
570 catch( const uno::Exception & )
573 return xRet;
576 rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex
577 , const rtl::Reference< BaseCoordinateSystem >& xCooSys )
579 rtl::Reference< Axis > xRet;
580 if(!xCooSys.is())
581 return xRet;
583 if(nDimensionIndex >= xCooSys->getDimension())
584 return xRet;
586 if(nAxisIndex > xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex))
587 return xRet;
589 assert(nAxisIndex >= 0);
590 assert(nDimensionIndex >= 0);
591 xRet = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex );
592 return xRet;
595 rtl::Reference< Axis > AxisHelper::getCrossingMainAxis( const rtl::Reference< Axis >& xAxis
596 , const rtl::Reference< BaseCoordinateSystem >& xCooSys )
598 sal_Int32 nDimensionIndex = 0;
599 sal_Int32 nAxisIndex = 0;
600 AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex );
601 if( nDimensionIndex==2 )
603 nDimensionIndex=1;
604 bool bSwapXY = false;
605 if( (xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXY) && bSwapXY )
606 nDimensionIndex=0;
608 else if( nDimensionIndex==1 )
609 nDimensionIndex=0;
610 else
611 nDimensionIndex=1;
612 return AxisHelper::getAxis( nDimensionIndex, 0, xCooSys );
615 rtl::Reference< Axis > AxisHelper::getParallelAxis( const rtl::Reference< Axis >& xAxis
616 , const rtl::Reference< Diagram >& xDiagram )
620 sal_Int32 nCooSysIndex=-1;
621 sal_Int32 nDimensionIndex=-1;
622 sal_Int32 nAxisIndex=-1;
623 if( getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ) )
625 sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1;
626 return getAxis( nDimensionIndex, nParallelAxisIndex, getCoordinateSystemByIndex( xDiagram, nCooSysIndex ) );
629 catch( const uno::RuntimeException& )
632 return nullptr;
635 bool AxisHelper::isAxisShown( sal_Int32 nDimensionIndex, bool bMainAxis
636 , const rtl::Reference< Diagram >& xDiagram )
638 return AxisHelper::isAxisVisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) );
641 bool AxisHelper::isAxisVisible( const rtl::Reference< Axis >& xAxis )
643 bool bRet = false;
645 if( xAxis.is() )
647 xAxis->getPropertyValue( "Show" ) >>= bRet;
648 bRet = bRet && ( LinePropertiesHelper::IsLineVisible( xAxis )
649 || areAxisLabelsVisible( xAxis ) );
652 return bRet;
655 bool AxisHelper::areAxisLabelsVisible( const rtl::Reference< Axis >& xAxis )
657 bool bRet = false;
658 if( xAxis.is() )
660 xAxis->getPropertyValue( "DisplayLabels" ) >>= bRet;
662 return bRet;
665 bool AxisHelper::isGridVisible( const rtl::Reference< ::chart::GridProperties >& xGridproperties )
667 bool bRet = false;
669 if( xGridproperties.is() )
671 xGridproperties->getPropertyValue( "Show" ) >>= bRet;
672 bRet = bRet && LinePropertiesHelper::IsLineVisible( xGridproperties );
675 return bRet;
678 rtl::Reference< GridProperties > AxisHelper::getGridProperties(
679 const rtl::Reference< BaseCoordinateSystem >& xCooSys
680 , sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex, sal_Int32 nSubGridIndex )
682 rtl::Reference< GridProperties > xRet;
684 rtl::Reference< Axis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ) );
685 if( xAxis.is() )
687 if( nSubGridIndex<0 )
688 xRet = xAxis->getGridProperties2();
689 else
691 std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
692 if (nSubGridIndex < static_cast<sal_Int32>(aSubGrids.size()))
693 xRet = aSubGrids[nSubGridIndex];
697 return xRet;
700 sal_Int32 AxisHelper::getDimensionIndexOfAxis(
701 const rtl::Reference< Axis >& xAxis
702 , const rtl::Reference< Diagram >& xDiagram )
704 sal_Int32 nDimensionIndex = -1;
705 sal_Int32 nCooSysIndex = -1;
706 sal_Int32 nAxisIndex = -1;
707 AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex , nDimensionIndex, nAxisIndex );
708 return nDimensionIndex;
711 bool AxisHelper::getIndicesForAxis(
712 const rtl::Reference< Axis >& xAxis
713 , const rtl::Reference< BaseCoordinateSystem >& xCooSys
714 , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex )
716 //returns true if indices are found
718 rOutDimensionIndex = -1;
719 rOutAxisIndex = -1;
721 if( !xCooSys || !xAxis )
722 return false;
724 rtl::Reference< Axis > xCurrentAxis;
725 sal_Int32 nDimensionCount( xCooSys->getDimension() );
726 for( sal_Int32 nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ )
728 sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
729 for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ )
731 xCurrentAxis = xCooSys->getAxisByDimension2(nDimensionIndex,nAxisIndex);
732 if( xCurrentAxis == xAxis )
734 rOutDimensionIndex = nDimensionIndex;
735 rOutAxisIndex = nAxisIndex;
736 return true;
740 return false;
743 bool AxisHelper::getIndicesForAxis( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram
744 , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex )
746 //returns true if indices are found
748 rOutCooSysIndex = -1;
749 rOutDimensionIndex = -1;
750 rOutAxisIndex = -1;
752 const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList = xDiagram->getBaseCoordinateSystems();
753 for( std::size_t nC=0; nC < aCooSysList.size(); ++nC )
755 if( AxisHelper::getIndicesForAxis( xAxis, aCooSysList[nC], rOutDimensionIndex, rOutAxisIndex ) )
757 rOutCooSysIndex = nC;
758 return true;
762 return false;
765 std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfCoordinateSystem(
766 const rtl::Reference< BaseCoordinateSystem >& xCooSys
767 , bool bOnlyVisible /* = false */ )
769 std::vector< rtl::Reference< Axis > > aAxisVector;
771 if(xCooSys.is())
773 sal_Int32 nMaxDimensionIndex = xCooSys->getDimension() -1;
774 if( nMaxDimensionIndex>=0 )
776 sal_Int32 nDimensionIndex = 0;
777 for(; nDimensionIndex<=nMaxDimensionIndex; ++nDimensionIndex)
779 const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
780 for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex)
784 rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex );
785 if( xAxis.is() )
787 bool bAddAxis = true;
788 if( bOnlyVisible )
790 if( !(xAxis->getPropertyValue( "Show") >>= bAddAxis) )
791 bAddAxis = false;
793 if( bAddAxis )
794 aAxisVector.push_back( xAxis );
797 catch( const uno::Exception & )
799 DBG_UNHANDLED_EXCEPTION("chart2");
806 return aAxisVector;
809 std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfDiagram(
810 const rtl::Reference< Diagram >& xDiagram
811 , bool bOnlyVisible )
813 std::vector< rtl::Reference< Axis > > aAxisVector;
815 for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() )
817 std::vector< rtl::Reference< Axis > > aAxesPerCooSys = AxisHelper::getAllAxesOfCoordinateSystem( coords, bOnlyVisible );
818 aAxisVector.insert( aAxisVector.end(), aAxesPerCooSys.begin(), aAxesPerCooSys.end() );
821 return aAxisVector;
824 std::vector< rtl::Reference< GridProperties > > AxisHelper::getAllGrids( const rtl::Reference< Diagram >& xDiagram )
826 const std::vector< rtl::Reference< Axis > > aAllAxes = AxisHelper::getAllAxesOfDiagram( xDiagram );
827 std::vector< rtl::Reference< GridProperties > > aGridVector;
829 for( rtl::Reference< Axis > const & xAxis : aAllAxes )
831 rtl::Reference< GridProperties > xGridProperties( xAxis->getGridProperties2() );
832 if( xGridProperties.is() )
833 aGridVector.push_back( xGridProperties );
835 std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
836 for( rtl::Reference< GridProperties > const & xSubGrid : aSubGrids )
838 if( xSubGrid.is() )
839 aGridVector.push_back( xSubGrid );
843 return aGridVector;
846 void AxisHelper::getAxisOrGridPossibilities( Sequence< sal_Bool >& rPossibilityList
847 , const rtl::Reference< Diagram>& xDiagram, bool bAxis )
849 rPossibilityList.realloc(6);
850 sal_Bool* pPossibilityList = rPossibilityList.getArray();
852 sal_Int32 nDimensionCount = -1;
853 if (xDiagram)
854 nDimensionCount = xDiagram->getDimension();
856 //set possibilities:
857 sal_Int32 nIndex=0;
858 rtl::Reference< ChartType > xChartType;
859 if (xDiagram)
860 xChartType = xDiagram->getChartTypeByIndex( 0 );
861 for(nIndex=0;nIndex<3;nIndex++)
862 pPossibilityList[nIndex]=ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nIndex);
863 for(nIndex=3;nIndex<6;nIndex++)
864 if( bAxis )
865 pPossibilityList[nIndex]=ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount);
866 else
867 pPossibilityList[nIndex] = rPossibilityList[nIndex-3];
870 bool AxisHelper::isSecondaryYAxisNeeded( const rtl::Reference< BaseCoordinateSystem >& xCooSys )
872 if( !xCooSys.is() )
873 return false;
875 const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCooSys->getChartTypes2() );
876 for( rtl::Reference< ChartType > const & chartType : aChartTypes )
878 const std::vector< rtl::Reference< DataSeries > > & aSeriesList = chartType->getDataSeries2();
879 for( sal_Int32 nS = aSeriesList.size(); nS-- ; )
881 sal_Int32 nAttachedAxisIndex = 0;
882 if( ( aSeriesList[nS]->getPropertyValue( "AttachedAxisIndex" ) >>= nAttachedAxisIndex ) &&
883 nAttachedAxisIndex>0 )
884 return true;
887 return false;
890 bool AxisHelper::shouldAxisBeDisplayed( const rtl::Reference< Axis >& xAxis
891 , const rtl::Reference< BaseCoordinateSystem >& xCooSys )
893 bool bRet = false;
895 if( xAxis.is() && xCooSys.is() )
897 sal_Int32 nDimensionIndex=-1;
898 sal_Int32 nAxisIndex=-1;
899 if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) )
901 sal_Int32 nDimensionCount = xCooSys->getDimension();
902 rtl::Reference< ChartType > xChartType( AxisHelper::getChartTypeByIndex( xCooSys, 0 ) );
904 bool bMainAxis = (nAxisIndex==MAIN_AXIS_INDEX);
905 if( bMainAxis )
906 bRet = ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nDimensionIndex);
907 else
908 bRet = ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount);
912 return bRet;
915 void AxisHelper::getAxisOrGridExistence( Sequence< sal_Bool >& rExistenceList
916 , const rtl::Reference< Diagram>& xDiagram, bool bAxis )
918 rExistenceList.realloc(6);
919 sal_Bool* pExistenceList = rExistenceList.getArray();
921 if(bAxis)
923 sal_Int32 nN;
924 for(nN=0;nN<3;nN++)
925 pExistenceList[nN] = AxisHelper::isAxisShown( nN, true, xDiagram );
926 for(nN=3;nN<6;nN++)
927 pExistenceList[nN] = AxisHelper::isAxisShown( nN%3, false, xDiagram );
929 else
931 sal_Int32 nN;
933 for(nN=0;nN<3;nN++)
934 pExistenceList[nN] = AxisHelper::isGridShown( nN, 0, true, xDiagram );
935 for(nN=3;nN<6;nN++)
936 pExistenceList[nN] = AxisHelper::isGridShown( nN%3, 0, false, xDiagram );
940 bool AxisHelper::changeVisibilityOfAxes( const rtl::Reference< Diagram >& xDiagram
941 , const Sequence< sal_Bool >& rOldExistenceList
942 , const Sequence< sal_Bool >& rNewExistenceList
943 , const Reference< uno::XComponentContext >& xContext
944 , ReferenceSizeProvider * pRefSizeProvider )
946 bool bChanged = false;
947 for(sal_Int32 nN=0;nN<6;nN++)
949 if(rOldExistenceList[nN]!=rNewExistenceList[nN])
951 bChanged = true;
952 if(rNewExistenceList[nN])
954 AxisHelper::showAxis( nN%3, nN<3, xDiagram, xContext, pRefSizeProvider );
956 else
957 AxisHelper::hideAxis( nN%3, nN<3, xDiagram );
960 return bChanged;
963 bool AxisHelper::changeVisibilityOfGrids( const rtl::Reference< Diagram >& xDiagram
964 , const Sequence< sal_Bool >& rOldExistenceList
965 , const Sequence< sal_Bool >& rNewExistenceList )
967 bool bChanged = false;
968 for(sal_Int32 nN=0;nN<6;nN++)
970 if(rOldExistenceList[nN]!=rNewExistenceList[nN])
972 bChanged = true;
973 if(rNewExistenceList[nN])
974 AxisHelper::showGrid( nN%3, 0, nN<3, xDiagram );
975 else
976 AxisHelper::hideGrid( nN%3, 0, nN<3, xDiagram );
979 return bChanged;
982 rtl::Reference< BaseCoordinateSystem > AxisHelper::getCoordinateSystemOfAxis(
983 const rtl::Reference< Axis >& xAxis
984 , const rtl::Reference< Diagram >& xDiagram )
986 if (!xDiagram)
987 return nullptr;
989 rtl::Reference< BaseCoordinateSystem > xRet;
990 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() )
992 std::vector< rtl::Reference< Axis > > aAllAxis = AxisHelper::getAllAxesOfCoordinateSystem( xCooSys );
994 auto aFound = std::find( aAllAxis.begin(), aAllAxis.end(), xAxis );
995 if( aFound != aAllAxis.end())
997 xRet = xCooSys;
998 break;
1001 return xRet;
1004 rtl::Reference< ChartType > AxisHelper::getChartTypeByIndex( const rtl::Reference< BaseCoordinateSystem >& xCooSys, sal_Int32 nIndex )
1006 rtl::Reference< ChartType > xChartType;
1008 if( xCooSys.is() )
1010 const std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() );
1011 if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < aChartTypeList.size() )
1012 xChartType = aChartTypeList[nIndex];
1015 return xChartType;
1018 void AxisHelper::setRTLAxisLayout( const rtl::Reference< BaseCoordinateSystem >& xCooSys )
1020 if( !xCooSys.is() )
1021 return;
1023 bool bCartesian = xCooSys->getViewServiceName() == CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME;
1024 if( !bCartesian )
1025 return;
1027 bool bVertical = false;
1028 xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bVertical;
1030 sal_Int32 nHorizontalAxisDimension = bVertical ? 1 : 0;
1031 sal_Int32 nVerticalAxisDimension = bVertical ? 0 : 1;
1035 //reverse direction for horizontal main axis
1036 rtl::Reference< Axis > xHorizontalMainAxis = AxisHelper::getAxis( nHorizontalAxisDimension, MAIN_AXIS_INDEX, xCooSys );
1037 if( xHorizontalMainAxis.is() )
1039 chart2::ScaleData aScale = xHorizontalMainAxis->getScaleData();
1040 aScale.Orientation = chart2::AxisOrientation_REVERSE;
1041 xHorizontalMainAxis->setScaleData(aScale);
1044 //mathematical direction for vertical main axis
1045 rtl::Reference< Axis > xVerticalMainAxis = AxisHelper::getAxis( nVerticalAxisDimension, MAIN_AXIS_INDEX, xCooSys );
1046 if( xVerticalMainAxis.is() )
1048 chart2::ScaleData aScale = xVerticalMainAxis->getScaleData();
1049 aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL;
1050 xVerticalMainAxis->setScaleData(aScale);
1053 catch( const uno::Exception & )
1055 DBG_UNHANDLED_EXCEPTION("chart2" );
1060 //reverse direction for horizontal secondary axis
1061 rtl::Reference< Axis > xHorizontalSecondaryAxis = AxisHelper::getAxis( nHorizontalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys );
1062 if( xHorizontalSecondaryAxis.is() )
1064 chart2::ScaleData aScale = xHorizontalSecondaryAxis->getScaleData();
1065 aScale.Orientation = chart2::AxisOrientation_REVERSE;
1066 xHorizontalSecondaryAxis->setScaleData(aScale);
1069 //mathematical direction for vertical secondary axis
1070 rtl::Reference< Axis > xVerticalSecondaryAxis = AxisHelper::getAxis( nVerticalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys );
1071 if( xVerticalSecondaryAxis.is() )
1073 chart2::ScaleData aScale = xVerticalSecondaryAxis->getScaleData();
1074 aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL;
1075 xVerticalSecondaryAxis->setScaleData(aScale);
1078 catch( const uno::Exception & )
1080 DBG_UNHANDLED_EXCEPTION("chart2");
1084 rtl::Reference< ChartType > AxisHelper::getFirstChartTypeWithSeriesAttachedToAxisIndex( const rtl::Reference< Diagram >& xDiagram, const sal_Int32 nAttachedAxisIndex )
1086 rtl::Reference< ChartType > xChartType;
1087 std::vector< rtl::Reference< DataSeries > > aSeriesVector = xDiagram->getDataSeries();
1088 for (auto const& series : aSeriesVector)
1090 sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series);
1091 if( nAttachedAxisIndex == nCurrentIndex )
1093 xChartType = xDiagram->getChartTypeOfSeries(series);
1094 if(xChartType.is())
1095 break;
1098 return xChartType;
1101 bool AxisHelper::isAxisPositioningEnabled()
1103 const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(GetODFSaneDefaultVersion());
1104 return nCurrentVersion >= SvtSaveOptions::ODFSVER_012;
1107 } //namespace chart
1109 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */