Get the style color and number just once
[LibreOffice.git] / chart2 / source / tools / AxisHelper.cxx
blob90233baddfaedb3b62af0261bf8f7fd149f39fae
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/diagnose_ex.hxx>
54 #include <cstddef>
55 #include <map>
57 namespace chart
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::chart2;
61 using ::com::sun::star::uno::Reference;
62 using ::com::sun::star::uno::Sequence;
64 Reference< chart2::XScaling > AxisHelper::createLinearScaling()
66 return new LinearScaling( 1.0, 0.0 );
69 Reference< chart2::XScaling > AxisHelper::createLogarithmicScaling( double fBase )
71 return new LogarithmicScaling( fBase );
74 ScaleData AxisHelper::createDefaultScale()
76 ScaleData aScaleData;
77 aScaleData.AxisType = chart2::AxisType::REALNUMBER;
78 aScaleData.AutoDateAxis = true;
79 aScaleData.ShiftedCategoryPosition = false;
80 aScaleData.IncrementData.SubIncrements = { SubIncrement() };
81 return aScaleData;
84 void AxisHelper::removeExplicitScaling( ScaleData& rScaleData )
86 rScaleData.Minimum = rScaleData.Maximum = rScaleData.Origin = uno::Any();
87 rScaleData.Scaling = nullptr;
88 ScaleData aDefaultScale( createDefaultScale() );
89 rScaleData.IncrementData = aDefaultScale.IncrementData;
90 rScaleData.TimeIncrement = aDefaultScale.TimeIncrement;
93 bool AxisHelper::isLogarithmic( const Reference< XScaling >& xScaling )
95 Reference< lang::XServiceName > xServiceName( xScaling, uno::UNO_QUERY );
96 return xServiceName.is()
97 && xServiceName->getServiceName() == "com.sun.star.chart2.LogarithmicScaling";
100 chart2::ScaleData AxisHelper::getDateCheckedScale( const rtl::Reference< Axis >& xAxis, ChartModel& rModel )
102 ScaleData aScale = xAxis->getScaleData();
103 rtl::Reference< BaseCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( &rModel ) );
104 if( aScale.AutoDateAxis && aScale.AxisType == AxisType::CATEGORY )
106 sal_Int32 nDimensionIndex=0; sal_Int32 nAxisIndex=0;
107 AxisHelper::getIndicesForAxis(xAxis, xCooSys, nDimensionIndex, nAxisIndex );
108 bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionIndex );
109 if( bChartTypeAllowsDateAxis )
110 aScale.AxisType = AxisType::DATE;
112 if( aScale.AxisType == AxisType::DATE )
114 ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel );
115 if( !aExplicitCategoriesProvider.isDateAxis() )
116 aScale.AxisType = AxisType::CATEGORY;
118 return aScale;
121 void AxisHelper::checkDateAxis( chart2::ScaleData& rScale, ExplicitCategoriesProvider* pExplicitCategoriesProvider, bool bChartTypeAllowsDateAxis )
123 if( rScale.AutoDateAxis && rScale.AxisType == AxisType::CATEGORY && bChartTypeAllowsDateAxis )
125 rScale.AxisType = AxisType::DATE;
126 removeExplicitScaling( rScale );
128 if( rScale.AxisType == AxisType::DATE && (!pExplicitCategoriesProvider || !pExplicitCategoriesProvider->isDateAxis()) )
130 rScale.AxisType = AxisType::CATEGORY;
131 removeExplicitScaling( rScale );
135 sal_Int32 AxisHelper::getExplicitNumberFormatKeyForAxis(
136 const rtl::Reference< Axis >& xAxis
137 , const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem
138 , const rtl::Reference<ChartModel>& xChartDoc
139 , bool bSearchForParallelAxisIfNothingIsFound )
141 sal_Int32 nNumberFormatKey(0);
142 sal_Int32 nAxisIndex = 0;
143 sal_Int32 nDimensionIndex = 1;
144 AxisHelper::getIndicesForAxis( xAxis, xCorrespondingCoordinateSystem, nDimensionIndex, nAxisIndex );
146 if (!xAxis.is())
147 return 0;
149 bool bLinkToSource = true;
150 xAxis->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource;
151 xAxis->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey;
153 if (bLinkToSource)
155 bool bFormatSet = false;
156 //check whether we have a percent scale -> use percent format
157 if (xChartDoc)
159 ScaleData aData = AxisHelper::getDateCheckedScale( xAxis, *xChartDoc );
160 if( aData.AxisType==AxisType::PERCENT )
162 sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( xChartDoc );
163 if( nPercentFormat != -1 )
165 nNumberFormatKey = nPercentFormat;
166 bFormatSet = true;
169 else if( aData.AxisType==AxisType::DATE )
171 if( aData.Categories.is() )
173 Reference< data::XDataSequence > xSeq( aData.Categories->getValues());
174 if( xSeq.is() && !( xChartDoc.is() && xChartDoc->hasInternalDataProvider()) )
175 nNumberFormatKey = xSeq->getNumberFormatKeyByIndex( -1 );
176 else
177 nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc );
178 bFormatSet = true;
181 else if( xChartDoc.is() && xChartDoc->hasInternalDataProvider() && nDimensionIndex == 0 ) //maybe date axis
183 rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram() );
184 if( xDiagram->isSupportingDateAxis() )
186 nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc );
188 else
190 rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *xChartDoc );
191 if( xSource.is() )
193 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aXValues(
194 DataSeriesHelper::getAllDataSequencesByRole( xSource->getDataSequences(), u"values-x"_ustr ) );
195 if( aXValues.empty() )
197 uno::Reference< chart2::data::XLabeledDataSequence > xCategories( xDiagram->getCategories() );
198 if( xCategories.is() )
200 Reference< data::XDataSequence > xSeq( xCategories->getValues());
201 if( xSeq.is() )
203 bool bHasValidDoubles = false;
204 double fTest=0.0;
205 Sequence< uno::Any > aCats( xSeq->getData() );
206 sal_Int32 nCount = aCats.getLength();
207 for( sal_Int32 i = 0; i < nCount; ++i )
209 if( (aCats[i]>>=fTest) && !std::isnan(fTest) )
211 bHasValidDoubles=true;
212 break;
215 if( bHasValidDoubles )
216 nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc );
222 bFormatSet = true;
226 if( !bFormatSet )
228 std::map< sal_Int32, sal_Int32 > aKeyMap;
229 bool bNumberFormatKeyFoundViaAttachedData = false;
233 OUString aRoleToMatch;
234 if( nDimensionIndex == 0 )
235 aRoleToMatch = "values-x";
236 const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCorrespondingCoordinateSystem->getChartTypes2());
237 for( rtl::Reference< ChartType > const & chartType : aChartTypes )
239 if( nDimensionIndex != 0 )
240 aRoleToMatch = ChartTypeHelper::getRoleOfSequenceForYAxisNumberFormatDetection( chartType );
241 for( rtl::Reference< DataSeries > const & xDataSeries : chartType->getDataSeries2() )
243 if( nDimensionIndex == 1 )
245 //only take those series into account that are attached to this axis
246 sal_Int32 nAttachedAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
247 if( nAttachedAxisIndex != nAxisIndex )
248 continue;
251 Reference< data::XLabeledDataSequence > xLabeledSeq(
252 DataSeriesHelper::getDataSequenceByRole( xDataSeries, aRoleToMatch ) );
254 if( !xLabeledSeq.is() && nDimensionIndex==0 )
256 ScaleData aData = xAxis->getScaleData();
257 xLabeledSeq = aData.Categories;
260 if( xLabeledSeq.is() )
262 Reference< data::XDataSequence > xSeq( xLabeledSeq->getValues());
263 if( xSeq.is() )
265 sal_Int32 nKey = xSeq->getNumberFormatKeyByIndex( -1 );
266 // increase frequency
267 aKeyMap[ nKey ] ++;
273 catch( const uno::Exception & )
275 DBG_UNHANDLED_EXCEPTION("chart2");
278 if( ! aKeyMap.empty())
280 sal_Int32 nMaxFreq = 0;
281 // find most frequent key
282 for (auto const& elem : aKeyMap)
284 SAL_INFO(
285 "chart2.tools",
286 "NumberFormatKey " << elem.first << " appears "
287 << elem.second << " times");
288 // all values must at least be 1
289 if( elem.second > nMaxFreq )
291 nNumberFormatKey = elem.first;
292 bNumberFormatKeyFoundViaAttachedData = true;
293 nMaxFreq = elem.second;
298 if( bSearchForParallelAxisIfNothingIsFound )
300 //no format is set to this axis and no data is set to this axis
301 //--> try to obtain the format from the parallel y-axis
302 if( !bNumberFormatKeyFoundViaAttachedData && nDimensionIndex == 1 )
304 sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1;
305 rtl::Reference< Axis > xParallelAxis = AxisHelper::getAxis( 1, nParallelAxisIndex, xCorrespondingCoordinateSystem );
306 nNumberFormatKey = AxisHelper::getExplicitNumberFormatKeyForAxis(xParallelAxis, xCorrespondingCoordinateSystem, xChartDoc, false);
312 return nNumberFormatKey;
315 rtl::Reference< Axis > AxisHelper::createAxis(
316 sal_Int32 nDimensionIndex
317 , sal_Int32 nAxisIndex // 0==main or 1==secondary axis
318 , const rtl::Reference< BaseCoordinateSystem >& xCooSys
319 , const Reference< uno::XComponentContext > & xContext
320 , ReferenceSizeProvider * pRefSizeProvider )
322 if( !xContext.is() || !xCooSys.is() )
323 return nullptr;
324 if( nDimensionIndex >= xCooSys->getDimension() )
325 return nullptr;
327 rtl::Reference< Axis > xAxis = new Axis();
329 xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex );
331 if( nAxisIndex>0 )//when inserting secondary axes copy some things from the main axis
333 css::chart::ChartAxisPosition eNewAxisPos( css::chart::ChartAxisPosition_END );
335 rtl::Reference< Axis > xMainAxis = xCooSys->getAxisByDimension2( nDimensionIndex, 0 );
336 if( xMainAxis.is() )
338 ScaleData aScale = xAxis->getScaleData();
339 ScaleData aMainScale = xMainAxis->getScaleData();
341 aScale.AxisType = aMainScale.AxisType;
342 aScale.AutoDateAxis = aMainScale.AutoDateAxis;
343 aScale.Categories = aMainScale.Categories;
344 aScale.Orientation = aMainScale.Orientation;
345 aScale.ShiftedCategoryPosition = aMainScale.ShiftedCategoryPosition;
347 xAxis->setScaleData( aScale );
349 //ensure that the second axis is not placed on the main axis
350 css::chart::ChartAxisPosition eMainAxisPos( css::chart::ChartAxisPosition_ZERO );
351 xMainAxis->getPropertyValue(u"CrossoverPosition"_ustr) >>= eMainAxisPos;
352 if( eMainAxisPos == css::chart::ChartAxisPosition_END )
353 eNewAxisPos = css::chart::ChartAxisPosition_START;
356 xAxis->setPropertyValue(u"CrossoverPosition"_ustr, uno::Any(eNewAxisPos) );
361 // set correct initial AutoScale
362 if( pRefSizeProvider )
363 pRefSizeProvider->setValuesAtPropertySet( xAxis );
365 catch( const uno::Exception& )
367 TOOLS_WARN_EXCEPTION("chart2", "" );
369 return xAxis;
372 rtl::Reference< Axis > AxisHelper::createAxis( sal_Int32 nDimensionIndex, bool bMainAxis
373 , const rtl::Reference< Diagram >& xDiagram
374 , const Reference< uno::XComponentContext >& xContext
375 , ReferenceSizeProvider * pRefSizeProvider )
377 OSL_ENSURE( xContext.is(), "need a context to create an axis" );
378 if( !xContext.is() )
379 return nullptr;
381 sal_Int32 nAxisIndex = bMainAxis ? MAIN_AXIS_INDEX : SECONDARY_AXIS_INDEX;
382 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 );
384 // create axis
385 return AxisHelper::createAxis(
386 nDimensionIndex, nAxisIndex, xCooSys, xContext, pRefSizeProvider );
389 void AxisHelper::showAxis( sal_Int32 nDimensionIndex, bool bMainAxis
390 , const rtl::Reference< Diagram >& xDiagram
391 , const Reference< uno::XComponentContext >& xContext
392 , ReferenceSizeProvider * pRefSizeProvider )
394 if( !xDiagram.is() )
395 return;
397 bool bNewAxisCreated = false;
398 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram );
399 if( !xAxis.is() && xContext.is() )
401 // create axis
402 bNewAxisCreated = true;
403 xAxis = AxisHelper::createAxis( nDimensionIndex, bMainAxis, xDiagram, xContext, pRefSizeProvider );
406 OSL_ASSERT( xAxis.is());
407 if( !bNewAxisCreated ) //default is true already if created
408 AxisHelper::makeAxisVisible( xAxis );
411 void AxisHelper::showGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid
412 , const rtl::Reference< Diagram >& xDiagram )
414 if( !xDiagram.is() )
415 return;
417 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex );
418 if(!xCooSys.is())
419 return;
421 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys );
422 if(!xAxis.is())
424 //hhhh todo create axis without axis visibility
425 return;
428 if( bMainGrid )
429 AxisHelper::makeGridVisible( xAxis->getGridProperties2() );
430 else
432 std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
433 for( auto const & i : aSubGrids )
434 AxisHelper::makeGridVisible( i );
438 void AxisHelper::makeAxisVisible( const rtl::Reference< Axis >& xAxis )
440 if( xAxis.is() )
442 xAxis->setPropertyValue( u"Show"_ustr, uno::Any( true ) );
443 LinePropertiesHelper::SetLineVisible( xAxis );
444 xAxis->setPropertyValue( u"DisplayLabels"_ustr, uno::Any( true ) );
448 void AxisHelper::makeGridVisible( const rtl::Reference< GridProperties >& xGridProperties )
450 if( xGridProperties.is() )
452 xGridProperties->setPropertyValue( u"Show"_ustr, uno::Any( true ) );
453 LinePropertiesHelper::SetLineVisible( xGridProperties );
457 void AxisHelper::hideAxis( sal_Int32 nDimensionIndex, bool bMainAxis
458 , const rtl::Reference< Diagram >& xDiagram )
460 AxisHelper::makeAxisInvisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) );
463 void AxisHelper::makeAxisInvisible( const rtl::Reference< Axis >& xAxis )
465 if( xAxis.is() )
467 xAxis->setPropertyValue( u"Show"_ustr, uno::Any( false ) );
471 void AxisHelper::hideAxisIfNoDataIsAttached( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram )
473 //axis is hidden if no data is attached anymore but data is available
474 bool bOtherSeriesAttachedToThisAxis = false;
475 std::vector< rtl::Reference< DataSeries > > aSeriesVector = xDiagram->getDataSeries();
476 for (auto const& series : aSeriesVector)
478 rtl::Reference< Axis > xCurrentAxis = xDiagram->getAttachedAxis(series);
479 if( xCurrentAxis==xAxis )
481 bOtherSeriesAttachedToThisAxis = true;
482 break;
485 if(!bOtherSeriesAttachedToThisAxis && !aSeriesVector.empty() )
486 AxisHelper::makeAxisInvisible( xAxis );
489 void AxisHelper::hideGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid
490 , const rtl::Reference< Diagram >& xDiagram )
492 if( !xDiagram.is() )
493 return;
495 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex );
496 if(!xCooSys.is())
497 return;
499 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys );
500 if(!xAxis.is())
501 return;
503 if( bMainGrid )
504 AxisHelper::makeGridInvisible( xAxis->getGridProperties2() );
505 else
507 std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
508 for( auto const & i : aSubGrids)
509 AxisHelper::makeGridInvisible( i );
513 void AxisHelper::makeGridInvisible( const rtl::Reference< ::chart::GridProperties >& xGridProperties )
515 if( xGridProperties.is() )
517 xGridProperties->setPropertyValue( u"Show"_ustr, uno::Any( false ) );
521 bool AxisHelper::isGridShown( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid
522 , const rtl::Reference< Diagram >& xDiagram )
524 bool bRet = false;
526 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex );
527 if(!xCooSys.is())
528 return bRet;
530 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys );
531 if(!xAxis.is())
532 return bRet;
534 if( bMainGrid )
535 bRet = AxisHelper::isGridVisible( xAxis->getGridProperties2() );
536 else
538 std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
539 if( !aSubGrids.empty() )
540 bRet = AxisHelper::isGridVisible( aSubGrids[0] );
543 return bRet;
546 rtl::Reference< ::chart::BaseCoordinateSystem > AxisHelper::getCoordinateSystemByIndex(
547 const rtl::Reference< Diagram >& xDiagram, sal_Int32 nIndex )
549 if(!xDiagram.is())
550 return nullptr;
551 auto aCooSysList = xDiagram->getBaseCoordinateSystems();
552 if(0<=nIndex && o3tl::make_unsigned(nIndex) < aCooSysList.size())
553 return aCooSysList[nIndex];
554 return nullptr;
557 rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, bool bMainAxis
558 , const rtl::Reference< Diagram >& xDiagram )
560 rtl::Reference< Axis > xRet;
563 rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 );
564 xRet = AxisHelper::getAxis( nDimensionIndex, bMainAxis ? 0 : 1, xCooSys );
566 catch( const uno::Exception & )
569 return xRet;
572 rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex
573 , const rtl::Reference< BaseCoordinateSystem >& xCooSys )
575 rtl::Reference< Axis > xRet;
576 if(!xCooSys.is())
577 return xRet;
579 if(nDimensionIndex >= xCooSys->getDimension())
580 return xRet;
582 if(nAxisIndex > xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex))
583 return xRet;
585 assert(nAxisIndex >= 0);
586 assert(nDimensionIndex >= 0);
587 xRet = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex );
588 return xRet;
591 rtl::Reference< Axis > AxisHelper::getCrossingMainAxis( const rtl::Reference< Axis >& xAxis
592 , const rtl::Reference< BaseCoordinateSystem >& xCooSys )
594 sal_Int32 nDimensionIndex = 0;
595 sal_Int32 nAxisIndex = 0;
596 AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex );
597 if( nDimensionIndex==2 )
599 nDimensionIndex=1;
600 bool bSwapXY = false;
601 if( (xCooSys->getPropertyValue( u"SwapXAndYAxis"_ustr ) >>= bSwapXY) && bSwapXY )
602 nDimensionIndex=0;
604 else if( nDimensionIndex==1 )
605 nDimensionIndex=0;
606 else
607 nDimensionIndex=1;
608 return AxisHelper::getAxis( nDimensionIndex, 0, xCooSys );
611 rtl::Reference< Axis > AxisHelper::getParallelAxis( const rtl::Reference< Axis >& xAxis
612 , const rtl::Reference< Diagram >& xDiagram )
616 sal_Int32 nCooSysIndex=-1;
617 sal_Int32 nDimensionIndex=-1;
618 sal_Int32 nAxisIndex=-1;
619 if( getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ) )
621 sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1;
622 return getAxis( nDimensionIndex, nParallelAxisIndex, getCoordinateSystemByIndex( xDiagram, nCooSysIndex ) );
625 catch( const uno::RuntimeException& )
628 return nullptr;
631 bool AxisHelper::isAxisShown( sal_Int32 nDimensionIndex, bool bMainAxis
632 , const rtl::Reference< Diagram >& xDiagram )
634 return AxisHelper::isAxisVisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) );
637 bool AxisHelper::isAxisVisible( const rtl::Reference< Axis >& xAxis )
639 bool bRet = false;
641 if( xAxis.is() )
643 xAxis->getPropertyValue( u"Show"_ustr ) >>= bRet;
644 bRet = bRet && ( LinePropertiesHelper::IsLineVisible( xAxis )
645 || areAxisLabelsVisible( xAxis ) );
648 return bRet;
651 bool AxisHelper::areAxisLabelsVisible( const rtl::Reference< Axis >& xAxis )
653 bool bRet = false;
654 if( xAxis.is() )
656 xAxis->getPropertyValue( u"DisplayLabels"_ustr ) >>= bRet;
658 return bRet;
661 bool AxisHelper::isGridVisible( const rtl::Reference< ::chart::GridProperties >& xGridproperties )
663 bool bRet = false;
665 if( xGridproperties.is() )
667 xGridproperties->getPropertyValue( u"Show"_ustr ) >>= bRet;
668 bRet = bRet && LinePropertiesHelper::IsLineVisible( xGridproperties );
671 return bRet;
674 rtl::Reference< GridProperties > AxisHelper::getGridProperties(
675 const rtl::Reference< BaseCoordinateSystem >& xCooSys
676 , sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex, sal_Int32 nSubGridIndex )
678 rtl::Reference< GridProperties > xRet;
680 rtl::Reference< Axis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ) );
681 if( xAxis.is() )
683 if( nSubGridIndex<0 )
684 xRet = xAxis->getGridProperties2();
685 else
687 std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
688 if (nSubGridIndex < static_cast<sal_Int32>(aSubGrids.size()))
689 xRet = aSubGrids[nSubGridIndex];
693 return xRet;
696 sal_Int32 AxisHelper::getDimensionIndexOfAxis(
697 const rtl::Reference< Axis >& xAxis
698 , const rtl::Reference< Diagram >& xDiagram )
700 sal_Int32 nDimensionIndex = -1;
701 sal_Int32 nCooSysIndex = -1;
702 sal_Int32 nAxisIndex = -1;
703 AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex , nDimensionIndex, nAxisIndex );
704 return nDimensionIndex;
707 bool AxisHelper::getIndicesForAxis(
708 const rtl::Reference< Axis >& xAxis
709 , const rtl::Reference< BaseCoordinateSystem >& xCooSys
710 , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex )
712 //returns true if indices are found
714 rOutDimensionIndex = -1;
715 rOutAxisIndex = -1;
717 if( !xCooSys || !xAxis )
718 return false;
720 rtl::Reference< Axis > xCurrentAxis;
721 sal_Int32 nDimensionCount( xCooSys->getDimension() );
722 for( sal_Int32 nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ )
724 sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
725 for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ )
727 xCurrentAxis = xCooSys->getAxisByDimension2(nDimensionIndex,nAxisIndex);
728 if( xCurrentAxis == xAxis )
730 rOutDimensionIndex = nDimensionIndex;
731 rOutAxisIndex = nAxisIndex;
732 return true;
736 return false;
739 bool AxisHelper::getIndicesForAxis( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram
740 , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex )
742 //returns true if indices are found
744 rOutCooSysIndex = -1;
745 rOutDimensionIndex = -1;
746 rOutAxisIndex = -1;
748 const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysList = xDiagram->getBaseCoordinateSystems();
749 for( std::size_t nC=0; nC < aCooSysList.size(); ++nC )
751 if( AxisHelper::getIndicesForAxis( xAxis, aCooSysList[nC], rOutDimensionIndex, rOutAxisIndex ) )
753 rOutCooSysIndex = nC;
754 return true;
758 return false;
761 std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfCoordinateSystem(
762 const rtl::Reference< BaseCoordinateSystem >& xCooSys
763 , bool bOnlyVisible /* = false */ )
765 std::vector< rtl::Reference< Axis > > aAxisVector;
767 if(xCooSys.is())
769 sal_Int32 nMaxDimensionIndex = xCooSys->getDimension() -1;
770 if( nMaxDimensionIndex>=0 )
772 sal_Int32 nDimensionIndex = 0;
773 for(; nDimensionIndex<=nMaxDimensionIndex; ++nDimensionIndex)
775 const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
776 for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex)
780 rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex );
781 if( xAxis.is() )
783 bool bAddAxis = true;
784 if( bOnlyVisible )
786 if( !(xAxis->getPropertyValue( u"Show"_ustr) >>= bAddAxis) )
787 bAddAxis = false;
789 if( bAddAxis )
790 aAxisVector.push_back( xAxis );
793 catch( const uno::Exception & )
795 DBG_UNHANDLED_EXCEPTION("chart2");
802 return aAxisVector;
805 std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfDiagram(
806 const rtl::Reference< Diagram >& xDiagram
807 , bool bOnlyVisible )
809 std::vector< rtl::Reference< Axis > > aAxisVector;
811 for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() )
813 std::vector< rtl::Reference< Axis > > aAxesPerCooSys = AxisHelper::getAllAxesOfCoordinateSystem( coords, bOnlyVisible );
814 aAxisVector.insert( aAxisVector.end(), aAxesPerCooSys.begin(), aAxesPerCooSys.end() );
817 return aAxisVector;
820 std::vector< rtl::Reference< GridProperties > > AxisHelper::getAllGrids( const rtl::Reference< Diagram >& xDiagram )
822 const std::vector< rtl::Reference< Axis > > aAllAxes = AxisHelper::getAllAxesOfDiagram( xDiagram );
823 std::vector< rtl::Reference< GridProperties > > aGridVector;
825 for( rtl::Reference< Axis > const & xAxis : aAllAxes )
827 rtl::Reference< GridProperties > xGridProperties( xAxis->getGridProperties2() );
828 if( xGridProperties.is() )
829 aGridVector.push_back( xGridProperties );
831 std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
832 for( rtl::Reference< GridProperties > const & xSubGrid : aSubGrids )
834 if( xSubGrid.is() )
835 aGridVector.push_back( xSubGrid );
839 return aGridVector;
842 void AxisHelper::getAxisOrGridPossibilities( Sequence< sal_Bool >& rPossibilityList
843 , const rtl::Reference< Diagram>& xDiagram, bool bAxis )
845 rPossibilityList.realloc(6);
846 sal_Bool* pPossibilityList = rPossibilityList.getArray();
848 sal_Int32 nDimensionCount = -1;
849 if (xDiagram)
850 nDimensionCount = xDiagram->getDimension();
852 //set possibilities:
853 sal_Int32 nIndex=0;
854 rtl::Reference< ChartType > xChartType;
855 if (xDiagram)
856 xChartType = xDiagram->getChartTypeByIndex( 0 );
857 for(nIndex=0;nIndex<3;nIndex++)
858 pPossibilityList[nIndex]=ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nIndex);
859 for(nIndex=3;nIndex<6;nIndex++)
860 if( bAxis )
861 pPossibilityList[nIndex]=ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount);
862 else
863 pPossibilityList[nIndex] = rPossibilityList[nIndex-3];
866 bool AxisHelper::isSecondaryYAxisNeeded( const rtl::Reference< BaseCoordinateSystem >& xCooSys )
868 if( !xCooSys.is() )
869 return false;
871 const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCooSys->getChartTypes2() );
872 for( rtl::Reference< ChartType > const & chartType : aChartTypes )
874 const std::vector< rtl::Reference< DataSeries > > & aSeriesList = chartType->getDataSeries2();
875 for( sal_Int32 nS = aSeriesList.size(); nS-- ; )
877 sal_Int32 nAttachedAxisIndex = 0;
878 if( ( aSeriesList[nS]->getPropertyValue( u"AttachedAxisIndex"_ustr ) >>= nAttachedAxisIndex ) &&
879 nAttachedAxisIndex>0 )
880 return true;
883 return false;
886 bool AxisHelper::shouldAxisBeDisplayed( const rtl::Reference< Axis >& xAxis
887 , const rtl::Reference< BaseCoordinateSystem >& xCooSys )
889 bool bRet = false;
891 if( xAxis.is() && xCooSys.is() )
893 sal_Int32 nDimensionIndex=-1;
894 sal_Int32 nAxisIndex=-1;
895 if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) )
897 sal_Int32 nDimensionCount = xCooSys->getDimension();
898 rtl::Reference< ChartType > xChartType( AxisHelper::getChartTypeByIndex( xCooSys, 0 ) );
900 bool bMainAxis = (nAxisIndex==MAIN_AXIS_INDEX);
901 if( bMainAxis )
902 bRet = ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nDimensionIndex);
903 else
904 bRet = ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount);
908 return bRet;
911 void AxisHelper::getAxisOrGridExistence( Sequence< sal_Bool >& rExistenceList
912 , const rtl::Reference< Diagram>& xDiagram, bool bAxis )
914 rExistenceList.realloc(6);
915 sal_Bool* pExistenceList = rExistenceList.getArray();
917 if(bAxis)
919 sal_Int32 nN;
920 for(nN=0;nN<3;nN++)
921 pExistenceList[nN] = AxisHelper::isAxisShown( nN, true, xDiagram );
922 for(nN=3;nN<6;nN++)
923 pExistenceList[nN] = AxisHelper::isAxisShown( nN%3, false, xDiagram );
925 else
927 sal_Int32 nN;
929 for(nN=0;nN<3;nN++)
930 pExistenceList[nN] = AxisHelper::isGridShown( nN, 0, true, xDiagram );
931 for(nN=3;nN<6;nN++)
932 pExistenceList[nN] = AxisHelper::isGridShown( nN%3, 0, false, xDiagram );
936 bool AxisHelper::changeVisibilityOfAxes( const rtl::Reference< Diagram >& xDiagram
937 , const Sequence< sal_Bool >& rOldExistenceList
938 , const Sequence< sal_Bool >& rNewExistenceList
939 , const Reference< uno::XComponentContext >& xContext
940 , ReferenceSizeProvider * pRefSizeProvider )
942 bool bChanged = false;
943 for(sal_Int32 nN=0;nN<6;nN++)
945 if(rOldExistenceList[nN]!=rNewExistenceList[nN])
947 bChanged = true;
948 if(rNewExistenceList[nN])
950 AxisHelper::showAxis( nN%3, nN<3, xDiagram, xContext, pRefSizeProvider );
952 else
953 AxisHelper::hideAxis( nN%3, nN<3, xDiagram );
956 return bChanged;
959 bool AxisHelper::changeVisibilityOfGrids( const rtl::Reference< Diagram >& xDiagram
960 , const Sequence< sal_Bool >& rOldExistenceList
961 , const Sequence< sal_Bool >& rNewExistenceList )
963 bool bChanged = false;
964 for(sal_Int32 nN=0;nN<6;nN++)
966 if(rOldExistenceList[nN]!=rNewExistenceList[nN])
968 bChanged = true;
969 if(rNewExistenceList[nN])
970 AxisHelper::showGrid( nN%3, 0, nN<3, xDiagram );
971 else
972 AxisHelper::hideGrid( nN%3, 0, nN<3, xDiagram );
975 return bChanged;
978 rtl::Reference< BaseCoordinateSystem > AxisHelper::getCoordinateSystemOfAxis(
979 const rtl::Reference< Axis >& xAxis
980 , const rtl::Reference< Diagram >& xDiagram )
982 if (!xDiagram)
983 return nullptr;
985 rtl::Reference< BaseCoordinateSystem > xRet;
986 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() )
988 std::vector< rtl::Reference< Axis > > aAllAxis = AxisHelper::getAllAxesOfCoordinateSystem( xCooSys );
990 auto aFound = std::find( aAllAxis.begin(), aAllAxis.end(), xAxis );
991 if( aFound != aAllAxis.end())
993 xRet = xCooSys;
994 break;
997 return xRet;
1000 rtl::Reference< ChartType > AxisHelper::getChartTypeByIndex( const rtl::Reference< BaseCoordinateSystem >& xCooSys, sal_Int32 nIndex )
1002 rtl::Reference< ChartType > xChartType;
1004 if( xCooSys.is() )
1006 const std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() );
1007 if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < aChartTypeList.size() )
1008 xChartType = aChartTypeList[nIndex];
1011 return xChartType;
1014 void AxisHelper::setRTLAxisLayout( const rtl::Reference< BaseCoordinateSystem >& xCooSys )
1016 if( !xCooSys.is() )
1017 return;
1019 bool bCartesian = xCooSys->getViewServiceName() == CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME;
1020 if( !bCartesian )
1021 return;
1023 bool bVertical = false;
1024 xCooSys->getPropertyValue( u"SwapXAndYAxis"_ustr ) >>= bVertical;
1026 sal_Int32 nHorizontalAxisDimension = bVertical ? 1 : 0;
1027 sal_Int32 nVerticalAxisDimension = bVertical ? 0 : 1;
1031 //reverse direction for horizontal main axis
1032 rtl::Reference< Axis > xHorizontalMainAxis = AxisHelper::getAxis( nHorizontalAxisDimension, MAIN_AXIS_INDEX, xCooSys );
1033 if( xHorizontalMainAxis.is() )
1035 chart2::ScaleData aScale = xHorizontalMainAxis->getScaleData();
1036 aScale.Orientation = chart2::AxisOrientation_REVERSE;
1037 xHorizontalMainAxis->setScaleData(aScale);
1040 //mathematical direction for vertical main axis
1041 rtl::Reference< Axis > xVerticalMainAxis = AxisHelper::getAxis( nVerticalAxisDimension, MAIN_AXIS_INDEX, xCooSys );
1042 if( xVerticalMainAxis.is() )
1044 chart2::ScaleData aScale = xVerticalMainAxis->getScaleData();
1045 aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL;
1046 xVerticalMainAxis->setScaleData(aScale);
1049 catch( const uno::Exception & )
1051 DBG_UNHANDLED_EXCEPTION("chart2" );
1056 //reverse direction for horizontal secondary axis
1057 rtl::Reference< Axis > xHorizontalSecondaryAxis = AxisHelper::getAxis( nHorizontalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys );
1058 if( xHorizontalSecondaryAxis.is() )
1060 chart2::ScaleData aScale = xHorizontalSecondaryAxis->getScaleData();
1061 aScale.Orientation = chart2::AxisOrientation_REVERSE;
1062 xHorizontalSecondaryAxis->setScaleData(aScale);
1065 //mathematical direction for vertical secondary axis
1066 rtl::Reference< Axis > xVerticalSecondaryAxis = AxisHelper::getAxis( nVerticalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys );
1067 if( xVerticalSecondaryAxis.is() )
1069 chart2::ScaleData aScale = xVerticalSecondaryAxis->getScaleData();
1070 aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL;
1071 xVerticalSecondaryAxis->setScaleData(aScale);
1074 catch( const uno::Exception & )
1076 DBG_UNHANDLED_EXCEPTION("chart2");
1080 rtl::Reference< ChartType > AxisHelper::getFirstChartTypeWithSeriesAttachedToAxisIndex( const rtl::Reference< Diagram >& xDiagram, const sal_Int32 nAttachedAxisIndex )
1082 rtl::Reference< ChartType > xChartType;
1083 std::vector< rtl::Reference< DataSeries > > aSeriesVector = xDiagram->getDataSeries();
1084 for (auto const& series : aSeriesVector)
1086 sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series);
1087 if( nAttachedAxisIndex == nCurrentIndex )
1089 xChartType = xDiagram->getChartTypeOfSeries(series);
1090 if(xChartType.is())
1091 break;
1094 return xChartType;
1097 bool AxisHelper::isAxisPositioningEnabled()
1099 const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(GetODFSaneDefaultVersion());
1100 return nCurrentVersion >= SvtSaveOptions::ODFSVER_012;
1103 } //namespace chart
1105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */