1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <DataSeriesHelper.hxx>
21 #include <DataSeries.hxx>
22 #include <DataSeriesProperties.hxx>
23 #include <DataSource.hxx>
24 #include <ChartType.hxx>
25 #include <unonames.hxx>
26 #include <Diagram.hxx>
27 #include <BaseCoordinateSystem.hxx>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/chart2/DataPointLabel.hpp>
32 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
33 #include <com/sun/star/chart2/StackingDirection.hpp>
34 #include <com/sun/star/chart2/data/LabelOrigin.hpp>
35 #include <com/sun/star/chart2/AxisType.hpp>
36 #include <com/sun/star/chart2/SymbolStyle.hpp>
37 #include <com/sun/star/chart2/Symbol.hpp>
38 #include <com/sun/star/chart2/XDiagram.hpp>
39 #include <com/sun/star/drawing/LineStyle.hpp>
41 #include <comphelper/sequence.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <comphelper/diagnose_ex.hxx>
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::chart2
;
53 using namespace ::chart::DataSeriesProperties
;
55 using ::com::sun::star::uno::Reference
;
56 using ::com::sun::star::uno::Sequence
;
64 explicit lcl_MatchesRole( OUString aRole
, bool bMatchPrefix
) :
65 m_aRole(std::move( aRole
)),
66 m_bMatchPrefix( bMatchPrefix
)
69 bool operator () ( const Reference
< chart2::data::XLabeledDataSequence
> & xSeq
) const
73 Reference
< beans::XPropertySet
> xProp( xSeq
->getValues(), uno::UNO_QUERY
);
77 return ( xProp
.is() &&
78 (xProp
->getPropertyValue( "Role" ) >>= aRole
) &&
79 aRole
.match( m_aRole
));
81 return ( xProp
.is() &&
82 (xProp
->getPropertyValue( "Role" ) >>= aRole
) &&
91 void lcl_getCooSysAndChartTypeOfSeries(
92 const rtl::Reference
< ::chart::DataSeries
> & xSeries
,
93 const Reference
< chart2::XDiagram
> & xDiagram
,
94 rtl::Reference
< ::chart::BaseCoordinateSystem
> & xOutCooSys
,
95 rtl::Reference
< ::chart::ChartType
> & xOutChartType
)
99 ::chart::Diagram
* pDiagram
= dynamic_cast<::chart::Diagram
*>(xDiagram
.get());
101 for( rtl::Reference
< ::chart::BaseCoordinateSystem
> const & coords
: pDiagram
->getBaseCoordinateSystems() )
103 for( rtl::Reference
< ::chart::ChartType
> const & chartType
: coords
->getChartTypes2() )
105 for( rtl::Reference
< ::chart::DataSeries
> const & dataSeries
: chartType
->getDataSeries2() )
107 if( dataSeries
== xSeries
)
110 xOutChartType
= chartType
;
117 void lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( const rtl::Reference
< ::chart::DataSeries
>& xSeries
, bool bInsert
)
123 DataPointLabel aLabelAtSeries
;
124 xSeries
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabelAtSeries
;
125 aLabelAtSeries
.ShowNumber
= bInsert
;
128 aLabelAtSeries
.ShowNumberInPercent
= false;
129 aLabelAtSeries
.ShowCategoryName
= false;
131 xSeries
->setPropertyValue(CHART_UNONAME_LABEL
, uno::Any(aLabelAtSeries
));
132 uno::Sequence
< sal_Int32
> aAttributedDataPointIndexList
;
133 // "AttributedDataPoints"
134 if( xSeries
->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS
) >>= aAttributedDataPointIndexList
)
136 for(sal_Int32 nN
=aAttributedDataPointIndexList
.getLength();nN
--;)
138 Reference
< beans::XPropertySet
> xPointProp( xSeries
->getDataPointByIndex(aAttributedDataPointIndexList
[nN
]) );
139 if( xPointProp
.is() )
141 DataPointLabel aLabel
;
142 xPointProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabel
;
143 aLabel
.ShowNumber
= bInsert
;
146 aLabel
.ShowNumberInPercent
= false;
147 aLabel
.ShowCategoryName
= false;
148 aLabel
.ShowCustomLabel
= false;
149 aLabel
.ShowSeriesName
= false;
151 xPointProp
->setPropertyValue(CHART_UNONAME_LABEL
, uno::Any(aLabel
));
152 xPointProp
->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS
, uno::Any());
158 catch(const uno::Exception
&)
160 TOOLS_WARN_EXCEPTION("chart2", "" );
164 } // anonymous namespace
166 namespace chart::DataSeriesHelper
169 OUString
getRole( const uno::Reference
< chart2::data::XLabeledDataSequence
>& xLabeledDataSequence
)
172 if( xLabeledDataSequence
.is() )
174 Reference
< beans::XPropertySet
> xProp( xLabeledDataSequence
->getValues(), uno::UNO_QUERY
);
176 xProp
->getPropertyValue( "Role" ) >>= aRet
;
181 uno::Reference
< chart2::data::XLabeledDataSequence
>
182 getDataSequenceByRole(
183 const Reference
< chart2::data::XDataSource
> & xSource
,
184 const OUString
& aRole
,
185 bool bMatchPrefix
/* = false */ )
187 uno::Reference
< chart2::data::XLabeledDataSequence
> aNoResult
;
190 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aLabeledSeq( xSource
->getDataSequences());
193 for (auto const & i
: aLabeledSeq
)
195 if (lcl_MatchesRole(aRole
, bMatchPrefix
)(i
))
199 catch (const lang::DisposedException
&)
201 TOOLS_WARN_EXCEPTION( "chart2", "unexpected exception caught" );
207 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> >
208 getAllDataSequencesByRole( const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > & aDataSequences
,
209 const OUString
& aRole
)
211 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResultVec
;
212 for (const auto & i
: aDataSequences
)
214 if (lcl_MatchesRole(aRole
, /*bMatchPrefix*/true)(i
))
215 aResultVec
.push_back(i
);
220 std::vector
< css::uno::Reference
< css::chart2::data::XLabeledDataSequence
> >
221 getAllDataSequencesByRole( const std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > & aDataSequences
,
222 const OUString
& aRole
)
224 std::vector
< css::uno::Reference
< css::chart2::data::XLabeledDataSequence
> > aResultVec
;
225 std::copy_if( aDataSequences
.begin(), aDataSequences
.end(),
226 std::back_inserter( aResultVec
),
227 lcl_MatchesRole(aRole
, /*bMatchPrefix*/true) );
231 std::vector
<uno::Reference
<chart2::data::XLabeledDataSequence
> >
232 getAllDataSequences( const std::vector
<rtl::Reference
<DataSeries
> >& aSeries
)
234 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aSeqVec
;
236 for( rtl::Reference
<DataSeries
> const & dataSeries
: aSeries
)
238 const std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > & aSeq( dataSeries
->getDataSequences2());
239 aSeqVec
.insert( aSeqVec
.end(), aSeq
.begin(), aSeq
.end() );
245 rtl::Reference
< DataSource
>
246 getDataSource( const std::vector
< rtl::Reference
< DataSeries
> > & aSeries
)
248 return new DataSource(getAllDataSequences(aSeries
));
251 void setStackModeAtSeries(
252 const std::vector
< rtl::Reference
< DataSeries
> > & aSeries
,
253 const rtl::Reference
< BaseCoordinateSystem
> & xCorrespondingCoordinateSystem
,
254 StackMode eStackMode
)
256 const uno::Any
aPropValue(
257 ( (eStackMode
== StackMode::YStacked
) ||
258 (eStackMode
== StackMode::YStackedPercent
) )
259 ? chart2::StackingDirection_Y_STACKING
260 : (eStackMode
== StackMode::ZStacked
)
261 ? chart2::StackingDirection_Z_STACKING
262 : chart2::StackingDirection_NO_STACKING
);
264 std::set
< sal_Int32
> aAxisIndexSet
;
265 for( rtl::Reference
< DataSeries
> const & dataSeries
: aSeries
)
269 if( dataSeries
.is() )
271 dataSeries
->setPropertyValue( "StackingDirection", aPropValue
);
273 sal_Int32 nAxisIndex
= 0;
274 dataSeries
->getPropertyValue( "AttachedAxisIndex" ) >>= nAxisIndex
;
275 aAxisIndexSet
.insert(nAxisIndex
);
278 catch( const uno::Exception
& )
280 DBG_UNHANDLED_EXCEPTION("chart2");
284 if( !(xCorrespondingCoordinateSystem
.is() &&
285 1 < xCorrespondingCoordinateSystem
->getDimension()) )
288 if( aAxisIndexSet
.empty() )
290 aAxisIndexSet
.insert(0);
293 for (auto const& axisIndex
: aAxisIndexSet
)
295 rtl::Reference
< Axis
> xAxis
=
296 xCorrespondingCoordinateSystem
->getAxisByDimension2(1, axisIndex
);
299 bool bPercent
= (eStackMode
== StackMode::YStackedPercent
);
300 chart2::ScaleData aScaleData
= xAxis
->getScaleData();
302 if( bPercent
!= (aScaleData
.AxisType
==chart2::AxisType::PERCENT
) )
305 aScaleData
.AxisType
= chart2::AxisType::PERCENT
;
307 aScaleData
.AxisType
= chart2::AxisType::REALNUMBER
;
308 xAxis
->setScaleData( aScaleData
);
314 sal_Int32
getAttachedAxisIndex( const rtl::Reference
< DataSeries
> & xSeries
)
321 xSeries
->getPropertyValue( "AttachedAxisIndex" ) >>= nRet
;
324 catch( const uno::Exception
& )
326 DBG_UNHANDLED_EXCEPTION("chart2");
331 sal_Int32
getNumberFormatKeyFromAxis(
332 const rtl::Reference
< DataSeries
> & xSeries
,
333 const rtl::Reference
< BaseCoordinateSystem
> & xCorrespondingCoordinateSystem
,
334 sal_Int32 nDimensionIndex
,
335 sal_Int32 nAxisIndex
/* = -1 */ )
337 sal_Int32 nResult
= 0;
338 if( nAxisIndex
== -1 )
339 nAxisIndex
= getAttachedAxisIndex( xSeries
);
342 rtl::Reference
< Axis
> xAxisProp
=
343 xCorrespondingCoordinateSystem
->getAxisByDimension2( nDimensionIndex
, nAxisIndex
);
345 xAxisProp
->getPropertyValue(CHART_UNONAME_NUMFMT
) >>= nResult
;
347 catch( const uno::Exception
& )
349 DBG_UNHANDLED_EXCEPTION("chart2");
355 rtl::Reference
< ::chart::BaseCoordinateSystem
> getCoordinateSystemOfSeries(
356 const rtl::Reference
< DataSeries
> & xSeries
,
357 const rtl::Reference
< Diagram
> & xDiagram
)
359 rtl::Reference
< ::chart::BaseCoordinateSystem
> xResult
;
360 rtl::Reference
< ::chart::ChartType
> xDummy
;
361 lcl_getCooSysAndChartTypeOfSeries( xSeries
, xDiagram
, xResult
, xDummy
);
366 rtl::Reference
< ::chart::ChartType
> getChartTypeOfSeries(
367 const rtl::Reference
< DataSeries
> & xSeries
,
368 const rtl::Reference
< Diagram
> & xDiagram
)
370 rtl::Reference
< ::chart::ChartType
> xResult
;
371 rtl::Reference
< ::chart::BaseCoordinateSystem
> xDummy
;
372 lcl_getCooSysAndChartTypeOfSeries( xSeries
, xDiagram
, xDummy
, xResult
);
378 const rtl::Reference
< ::chart::DataSeries
> & xSeries
,
379 const rtl::Reference
< ::chart::ChartType
> & xChartType
)
383 std::vector
< rtl::Reference
< DataSeries
> > aSeries
= xChartType
->getDataSeries2();
384 auto aIt
= std::find( aSeries
.begin(), aSeries
.end(), xSeries
);
385 if( aIt
!= aSeries
.end())
387 aSeries
.erase( aIt
);
388 xChartType
->setDataSeries( aSeries
);
391 catch( const uno::Exception
& )
393 DBG_UNHANDLED_EXCEPTION("chart2");
397 void switchSymbolsOnOrOff( const rtl::Reference
< DataSeries
> & xSeries
,
398 bool bSymbolsOn
, sal_Int32 nSeriesIndex
)
403 chart2::Symbol aSymbProp
;
404 if( xSeries
->getPropertyValue( "Symbol") >>= aSymbProp
)
407 aSymbProp
.Style
= chart2::SymbolStyle_NONE
;
408 else if( aSymbProp
.Style
== chart2::SymbolStyle_NONE
)
410 aSymbProp
.Style
= chart2::SymbolStyle_STANDARD
;
411 aSymbProp
.StandardSymbol
= nSeriesIndex
;
413 xSeries
->setPropertyValue( "Symbol", uno::Any( aSymbProp
));
415 //todo: check attributed data points
418 void switchLinesOnOrOff( const rtl::Reference
< DataSeries
> & xSeries
, bool bLinesOn
)
425 // keep line-styles that are not NONE
426 drawing::LineStyle eLineStyle
;
427 if( (xSeries
->getPropertyValue( "LineStyle") >>= eLineStyle
) &&
428 eLineStyle
== drawing::LineStyle_NONE
)
430 xSeries
->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID
) );
434 xSeries
->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE
) );
437 void makeLinesThickOrThin( const rtl::Reference
< ::chart::DataSeries
> & xSeries
, bool bThick
)
442 sal_Int32 nNewValue
= bThick
? 80 : 0;
443 sal_Int32 nOldValue
= 0;
444 if( (xSeries
->getPropertyValue( "LineWidth") >>= nOldValue
) &&
445 nOldValue
!= nNewValue
)
447 if( !(bThick
&& nOldValue
>0))
448 xSeries
->setPropertyValue( "LineWidth", uno::Any( nNewValue
) );
452 void setPropertyAlsoToAllAttributedDataPoints( const rtl::Reference
< ::chart::DataSeries
>& xSeries
,
453 const OUString
& rPropertyName
, const uno::Any
& rPropertyValue
)
458 xSeries
->setPropertyValue( rPropertyName
, rPropertyValue
);
459 uno::Sequence
< sal_Int32
> aAttributedDataPointIndexList
;
460 // "AttributedDataPoints"
461 if( xSeries
->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS
) >>= aAttributedDataPointIndexList
)
463 for(sal_Int32 nN
=aAttributedDataPointIndexList
.getLength();nN
--;)
465 Reference
< beans::XPropertySet
> xPointProp( xSeries
->getDataPointByIndex(aAttributedDataPointIndexList
[nN
]) );
468 xPointProp
->setPropertyValue( rPropertyName
, rPropertyValue
);
469 if( rPropertyName
== "LabelPlacement" )
470 xPointProp
->setPropertyValue("CustomLabelPosition", uno::Any());
475 bool hasAttributedDataPointDifferentValue( const rtl::Reference
< DataSeries
>& xSeries
,
476 const OUString
& rPropertyName
, const uno::Any
& rPropertyValue
)
481 uno::Sequence
< sal_Int32
> aAttributedDataPointIndexList
;
482 // "AttributedDataPoints"
483 if( xSeries
->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS
) >>= aAttributedDataPointIndexList
)
485 for(sal_Int32 nN
=aAttributedDataPointIndexList
.getLength();nN
--;)
487 Reference
< beans::XPropertySet
> xPointProp( xSeries
->getDataPointByIndex(aAttributedDataPointIndexList
[nN
]) );
490 uno::Any
aPointValue( xPointProp
->getPropertyValue( rPropertyName
) );
491 if( rPropertyValue
!= aPointValue
)
503 sal_Int32
translateIndexFromHiddenToFullSequence( sal_Int32 nIndex
, const Reference
< chart2::data::XDataSequence
>& xDataSequence
, bool bTranslate
)
510 uno::Reference
<beans::XPropertySet
> xProp( xDataSequence
, uno::UNO_QUERY
);
513 Sequence
<sal_Int32
> aHiddenIndicesSeq
;
514 xProp
->getPropertyValue( "HiddenValues" ) >>= aHiddenIndicesSeq
;
515 if( aHiddenIndicesSeq
.hasElements() )
517 auto aHiddenIndices( comphelper::sequenceToContainer
<std::vector
< sal_Int32
>>( aHiddenIndicesSeq
) );
518 std::sort( aHiddenIndices
.begin(), aHiddenIndices
.end() );
520 sal_Int32 nHiddenCount
= static_cast<sal_Int32
>(aHiddenIndices
.size());
521 for( sal_Int32 nN
= 0; nN
< nHiddenCount
; ++nN
)
523 if( aHiddenIndices
[nN
] <= nIndex
)
531 catch (const beans::UnknownPropertyException
&)
537 bool hasDataLabelsAtSeries( const rtl::Reference
< DataSeries
>& xSeries
)
544 DataPointLabel aLabel
;
545 if( xSeries
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabel
)
546 bRet
= aLabel
.ShowNumber
|| aLabel
.ShowNumberInPercent
|| aLabel
.ShowCategoryName
547 || aLabel
.ShowSeriesName
;
550 catch(const uno::Exception
&)
552 TOOLS_WARN_EXCEPTION("chart2", "" );
557 bool hasDataLabelsAtPoints( const rtl::Reference
< DataSeries
>& xSeries
)
564 uno::Sequence
< sal_Int32
> aAttributedDataPointIndexList
;
565 // "AttributedDataPoints"
566 if( xSeries
->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS
) >>= aAttributedDataPointIndexList
)
568 for(sal_Int32 nN
=aAttributedDataPointIndexList
.getLength();nN
--;)
570 Reference
< beans::XPropertySet
> xPointProp( xSeries
->getDataPointByIndex(aAttributedDataPointIndexList
[nN
]) );
571 if( xPointProp
.is() )
573 DataPointLabel aLabel
;
574 if( xPointProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabel
)
575 bRet
= aLabel
.ShowNumber
|| aLabel
.ShowNumberInPercent
576 || aLabel
.ShowCategoryName
|| aLabel
.ShowCustomLabel
577 || aLabel
.ShowSeriesName
;
585 catch(const uno::Exception
&)
587 TOOLS_WARN_EXCEPTION("chart2", "" );
592 bool hasDataLabelAtPoint( const rtl::Reference
< DataSeries
>& xSeries
, sal_Int32 nPointIndex
)
597 Reference
< beans::XPropertySet
> xProp
;
600 uno::Sequence
< sal_Int32
> aAttributedDataPointIndexList
;
601 // "AttributedDataPoints"
602 if( xSeries
->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS
) >>= aAttributedDataPointIndexList
)
604 auto aIt
= std::find( std::as_const(aAttributedDataPointIndexList
).begin(), std::as_const(aAttributedDataPointIndexList
).end(), nPointIndex
);
605 if( aIt
!= std::as_const(aAttributedDataPointIndexList
).end())
606 xProp
= xSeries
->getDataPointByIndex(nPointIndex
);
612 DataPointLabel aLabel
;
613 if( xProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabel
)
614 bRet
= aLabel
.ShowNumber
|| aLabel
.ShowNumberInPercent
615 || aLabel
.ShowCategoryName
|| aLabel
.ShowCustomLabel
616 || aLabel
.ShowSeriesName
;
620 catch(const uno::Exception
&)
622 TOOLS_WARN_EXCEPTION("chart2", "" );
627 void insertDataLabelsToSeriesAndAllPoints( const rtl::Reference
< DataSeries
>& xSeries
)
629 lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries
, true /*bInsert*/ );
632 void deleteDataLabelsFromSeriesAndAllPoints( const rtl::Reference
< DataSeries
>& xSeries
)
634 lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries
, false /*bInsert*/ );
637 void insertDataLabelToPoint( const Reference
< beans::XPropertySet
>& xPointProp
)
641 if( xPointProp
.is() )
643 DataPointLabel aLabel
;
644 xPointProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabel
;
645 aLabel
.ShowNumber
= true;
646 xPointProp
->setPropertyValue(CHART_UNONAME_LABEL
, uno::Any(aLabel
));
649 catch(const uno::Exception
&)
651 TOOLS_WARN_EXCEPTION("chart2", "" );
655 void deleteDataLabelsFromPoint( const Reference
< beans::XPropertySet
>& xPointProp
)
659 if( xPointProp
.is() )
661 DataPointLabel aLabel
;
662 xPointProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= aLabel
;
663 aLabel
.ShowNumber
= false;
664 aLabel
.ShowNumberInPercent
= false;
665 aLabel
.ShowCategoryName
= false;
666 aLabel
.ShowCustomLabel
= false;
667 aLabel
.ShowSeriesName
= false;
668 xPointProp
->setPropertyValue(CHART_UNONAME_LABEL
, uno::Any(aLabel
));
669 xPointProp
->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS
, uno::Any());
672 catch(const uno::Exception
&)
674 TOOLS_WARN_EXCEPTION("chart2", "" );
680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */