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 <DataSourceHelper.hxx>
21 #include <ChartModel.hxx>
22 #include <ChartModelHelper.hxx>
23 #include <ChartTypeManager.hxx>
24 #include <Diagram.hxx>
25 #include <DataSeries.hxx>
26 #include <DataSeriesHelper.hxx>
27 #include <DataSource.hxx>
28 #include <ControllerLockGuard.hxx>
29 #include <CachedDataSequence.hxx>
30 #include <LabeledDataSequence.hxx>
31 #include <unonames.hxx>
33 #include <com/sun/star/chart2/data/XDataSource.hpp>
34 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
36 #include <com/sun/star/chart/ChartDataRowSource.hpp>
37 #include <com/sun/star/chart/ErrorBarStyle.hpp>
38 #include <comphelper/diagnose_ex.hxx>
42 using namespace ::com::sun::star
;
43 using namespace ::com::sun::star::chart2
;
44 using ::com::sun::star::uno::Reference
;
45 using ::com::sun::star::uno::Sequence
;
49 void lcl_addRanges( std::vector
< OUString
> & rOutResult
,
50 const uno::Reference
< data::XLabeledDataSequence
> & xLabeledSeq
)
52 if( ! xLabeledSeq
.is())
54 uno::Reference
< data::XDataSequence
> xSeq( xLabeledSeq
->getLabel());
56 rOutResult
.push_back( xSeq
->getSourceRangeRepresentation());
57 xSeq
.set( xLabeledSeq
->getValues());
59 rOutResult
.push_back( xSeq
->getSourceRangeRepresentation());
62 void lcl_addDataSourceRanges(
63 std::vector
< OUString
> & rOutResult
,
64 const uno::Reference
< data::XDataSource
> & xDataSource
)
66 if( xDataSource
.is() )
68 const auto aDataSequences(xDataSource
->getDataSequences());
69 for (const auto& rDataSequence
: aDataSequences
)
70 lcl_addRanges(rOutResult
, rDataSequence
);
74 void lcl_addErrorBarRanges(
75 std::vector
< OUString
> & rOutResult
,
76 const rtl::Reference
< DataSeries
> & xDataSeries
)
78 if( !xDataSeries
.is())
83 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
84 if( ( xDataSeries
->getPropertyValue( CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
) &&
87 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
88 if( ( xErrorBarProp
->getPropertyValue( u
"ErrorBarStyle"_ustr
) >>= eStyle
) &&
89 eStyle
== css::chart::ErrorBarStyle::FROM_DATA
)
91 uno::Reference
< data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
92 if( xErrorBarDataSource
.is() )
93 lcl_addDataSourceRanges( rOutResult
, xErrorBarDataSource
);
97 if( ( xDataSeries
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
) && xErrorBarProp
.is())
99 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
100 if( ( xErrorBarProp
->getPropertyValue(u
"ErrorBarStyle"_ustr
) >>= eStyle
) &&
101 eStyle
== css::chart::ErrorBarStyle::FROM_DATA
)
103 uno::Reference
< data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
104 if( xErrorBarDataSource
.is() )
105 lcl_addDataSourceRanges( rOutResult
, xErrorBarDataSource
);
109 catch( const uno::Exception
& )
111 DBG_UNHANDLED_EXCEPTION("chart2");
115 } // anonymous namespace
117 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence()
119 return new ::chart::CachedDataSequence();
122 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence( const OUString
& rSingleText
)
124 return new ::chart::CachedDataSequence( rSingleText
);
127 rtl::Reference
< LabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
128 const Reference
< chart2::data::XDataSequence
>& xValues
,
129 const Reference
< chart2::data::XDataSequence
>& xLabels
)
131 return new ::chart::LabeledDataSequence( xValues
, xLabels
);
134 rtl::Reference
< LabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
135 const Reference
< chart2::data::XDataSequence
>& xValues
)
137 return new ::chart::LabeledDataSequence( xValues
);
140 rtl::Reference
< LabeledDataSequence
> DataSourceHelper::createLabeledDataSequence()
142 return new ::chart::LabeledDataSequence
;
145 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
146 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
148 css::chart::ChartDataRowSource eRowSource
= css::chart::ChartDataRowSource_ROWS
;
150 eRowSource
= css::chart::ChartDataRowSource_COLUMNS
;
154 { u
"DataRowSource"_ustr
, -1, uno::Any( eRowSource
), beans::PropertyState_DIRECT_VALUE
},
155 { u
"FirstCellAsLabel"_ustr
, -1, uno::Any( bFirstCellAsLabel
), beans::PropertyState_DIRECT_VALUE
},
156 { u
"HasCategories"_ustr
, -1, uno::Any( bHasCategories
), beans::PropertyState_DIRECT_VALUE
}
160 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
161 const OUString
& rRangeRepresentation
,
162 const uno::Sequence
< sal_Int32
>& rSequenceMapping
,
163 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
165 uno::Sequence
< beans::PropertyValue
> aArguments( createArguments( bUseColumns
, bFirstCellAsLabel
, bHasCategories
));
166 aArguments
.realloc( aArguments
.getLength() + 1 );
167 aArguments
.getArray()[aArguments
.getLength() - 1] =
168 beans::PropertyValue( u
"CellRangeRepresentation"_ustr
169 , -1, uno::Any( rRangeRepresentation
)
170 , beans::PropertyState_DIRECT_VALUE
);
171 if( rSequenceMapping
.hasElements() )
173 aArguments
.realloc( aArguments
.getLength() + 1 );
174 aArguments
.getArray()[aArguments
.getLength() - 1] =
175 beans::PropertyValue( u
"SequenceMapping"_ustr
176 , -1, uno::Any( rSequenceMapping
)
177 , beans::PropertyState_DIRECT_VALUE
);
182 void DataSourceHelper::readArguments( const uno::Sequence
< beans::PropertyValue
>& rArguments
183 , OUString
& rRangeRepresentation
, uno::Sequence
< sal_Int32
>& rSequenceMapping
184 , bool& bUseColumns
, bool& bFirstCellAsLabel
, bool& bHasCategories
)
186 for(const beans::PropertyValue
& rProperty
: rArguments
)
188 if ( rProperty
.Name
== "DataRowSource" )
190 css::chart::ChartDataRowSource eRowSource
;
191 if( rProperty
.Value
>>= eRowSource
)
192 bUseColumns
= (eRowSource
==css::chart::ChartDataRowSource_COLUMNS
);
194 else if ( rProperty
.Name
== "FirstCellAsLabel" )
196 rProperty
.Value
>>= bFirstCellAsLabel
;
198 else if ( rProperty
.Name
== "HasCategories" )
200 rProperty
.Value
>>= bHasCategories
;
202 else if ( rProperty
.Name
== "CellRangeRepresentation" )
204 rProperty
.Value
>>= rRangeRepresentation
;
206 else if ( rProperty
.Name
== "SequenceMapping" )
208 rProperty
.Value
>>= rSequenceMapping
;
213 rtl::Reference
< DataSource
> DataSourceHelper::pressUsedDataIntoRectangularFormat(
214 const rtl::Reference
< ChartModel
>& xChartDoc
)
216 std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aResultVector
;
218 //categories are always the first sequence
219 rtl::Reference
< Diagram
> xDiagram( xChartDoc
->getFirstChartDiagram());
221 Reference
< chart2::data::XLabeledDataSequence
> xCategories
;
223 xCategories
= xDiagram
->getCategories();
224 if( xCategories
.is() )
225 aResultVector
.push_back( xCategories
);
227 std::vector
< rtl::Reference
< DataSeries
> > aSeriesVector
;
229 aSeriesVector
= xDiagram
->getDataSeries();
230 uno::Reference
< chart2::data::XDataSource
> xSeriesSource
=
231 DataSeriesHelper::getDataSource( aSeriesVector
);
232 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aDataSequences( xSeriesSource
->getDataSequences() );
234 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
235 Reference
< chart2::data::XLabeledDataSequence
> xXValues(
236 DataSeriesHelper::getDataSequenceByRole( xSeriesSource
, u
"values-x"_ustr
) );
238 aResultVector
.push_back( xXValues
);
240 //add all other sequences now without x-values
241 for( Reference
< chart2::data::XLabeledDataSequence
> const & labeledData
: aDataSequences
)
243 OUString aRole
= DataSeriesHelper::getRole(labeledData
);
244 if( aRole
!= "values-x" )
245 aResultVector
.push_back( labeledData
);
248 return new DataSource( aResultVector
);
251 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges(
252 const rtl::Reference
< Diagram
> & xDiagram
)
254 std::vector
< OUString
> aResult
;
258 uno::Reference
< data::XLabeledDataSequence
> xCategories( xDiagram
->getCategories() );
259 if( xCategories
.is() )
260 lcl_addRanges( aResult
, xCategories
);
262 std::vector
< rtl::Reference
< DataSeries
> > aSeriesVector( xDiagram
->getDataSeries() );
263 for (auto const& series
: aSeriesVector
)
265 lcl_addDataSourceRanges( aResult
, series
);
266 lcl_addErrorBarRanges( aResult
, series
);
270 return comphelper::containerToSequence( aResult
);
273 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges( const rtl::Reference
<::chart::ChartModel
> & xChartModel
)
275 rtl::Reference
< Diagram
> xDiagram( xChartModel
->getFirstChartDiagram() );
276 return getUsedDataRanges( xDiagram
);
279 rtl::Reference
< DataSource
> DataSourceHelper::getUsedData(
282 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResult
;
284 rtl::Reference
< Diagram
> xDiagram
= rModel
.getFirstChartDiagram();
285 uno::Reference
< chart2::data::XLabeledDataSequence
> xCategories( xDiagram
->getCategories() );
286 if( xCategories
.is() )
287 aResult
.push_back( xCategories
);
289 std::vector
< rtl::Reference
< DataSeries
> > aSeriesVector
= ChartModelHelper::getDataSeries( &rModel
);
290 for (auto const& series
: aSeriesVector
)
292 const std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > & aDataSequences( series
->getDataSequences2() );
293 aResult
.insert( aResult
.end(), aDataSequences
.begin(), aDataSequences
.end() );
296 return new DataSource( aResult
);
299 bool DataSourceHelper::detectRangeSegmentation(
300 const rtl::Reference
<::chart::ChartModel
>& xChartModel
301 , OUString
& rOutRangeString
302 , css::uno::Sequence
< sal_Int32
>& rSequenceMapping
303 , bool& rOutUseColumns
304 , bool& rOutFirstCellAsLabel
305 , bool& rOutHasCategories
)
307 bool bSomethingDetected
= false;
309 if( !xChartModel
.is() )
310 return bSomethingDetected
;
311 uno::Reference
< data::XDataProvider
> xDataProvider( xChartModel
->getDataProvider() );
312 if( !xDataProvider
.is() )
313 return bSomethingDetected
;
317 DataSourceHelper::readArguments(
318 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartModel
) ),
319 rOutRangeString
, rSequenceMapping
, rOutUseColumns
, rOutFirstCellAsLabel
, rOutHasCategories
);
320 bSomethingDetected
= !rOutRangeString
.isEmpty();
322 rtl::Reference
<Diagram
> xDiagram
= xChartModel
->getFirstChartDiagram();
323 uno::Reference
< chart2::data::XLabeledDataSequence
> xCategories
;
325 xCategories
= xDiagram
->getCategories();
326 rOutHasCategories
= xCategories
.is();
328 catch( uno::Exception
& )
330 DBG_UNHANDLED_EXCEPTION("chart2");
332 return bSomethingDetected
;
335 bool DataSourceHelper::allArgumentsForRectRangeDetected(
336 const rtl::Reference
<::chart::ChartModel
>& xChartDocument
)
338 bool bHasDataRowSource
= false;
339 bool bHasFirstCellAsLabel
= false;
340 bool bHasCellRangeRepresentation
= false;
342 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
343 if( !xDataProvider
.is() )
348 const uno::Sequence
< beans::PropertyValue
> aArguments(
349 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
)));
350 for(const beans::PropertyValue
& rProperty
: aArguments
)
352 if ( rProperty
.Name
== "DataRowSource" )
355 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(
356 cppu::UnoType
<css::chart::ChartDataRowSource
>::get()));
358 else if ( rProperty
.Name
== "FirstCellAsLabel" )
360 bHasFirstCellAsLabel
=
361 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(cppu::UnoType
<bool>::get()));
363 else if ( rProperty
.Name
== "CellRangeRepresentation" )
366 bHasCellRangeRepresentation
=
367 (rProperty
.Value
.hasValue() && (rProperty
.Value
>>= aRange
) && !aRange
.isEmpty());
371 catch( const uno::Exception
& )
373 DBG_UNHANDLED_EXCEPTION("chart2");
376 return (bHasCellRangeRepresentation
&& bHasDataRowSource
&& bHasFirstCellAsLabel
);
379 void DataSourceHelper::setRangeSegmentation(
380 const rtl::Reference
<::chart::ChartModel
>& xChartModel
381 , const css::uno::Sequence
< sal_Int32
>& rSequenceMapping
382 , bool bUseColumns
, bool bFirstCellAsLabel
, bool bUseCategories
)
384 uno::Reference
< data::XDataProvider
> xDataProvider( xChartModel
->getDataProvider() );
385 if( !xDataProvider
.is() )
387 rtl::Reference
< Diagram
> xDiagram( xChartModel
->getFirstChartDiagram() );
390 rtl::Reference
< ::chart::ChartTypeManager
> xChartTypeManager
= xChartModel
->getTypeManager();
391 if( !xChartTypeManager
.is() )
394 OUString aRangeString
;
396 uno::Sequence
< sal_Int32
> aDummy
;
397 readArguments( xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartModel
)),
398 aRangeString
, aDummy
, bDummy
, bDummy
, bDummy
);
400 uno::Sequence
< beans::PropertyValue
> aArguments(
401 createArguments( aRangeString
, rSequenceMapping
, bUseColumns
, bFirstCellAsLabel
, bUseCategories
) );
403 uno::Reference
< chart2::data::XDataSource
> xDataSource( xDataProvider
->createDataSource(
405 if( !xDataSource
.is() )
408 ControllerLockGuardUNO
aCtrlLockGuard( xChartModel
);
409 xDiagram
->setDiagramData( xDataSource
, aArguments
);
412 Sequence
< OUString
> DataSourceHelper::getRangesFromLabeledDataSequence(
413 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
415 Sequence
< OUString
> aResult
;
418 Reference
< data::XDataSequence
> xLabel( xLSeq
->getLabel());
419 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues());
425 aResult
= { xLabel
->getSourceRangeRepresentation(),
426 xValues
->getSourceRangeRepresentation() };
430 aResult
= { xLabel
->getSourceRangeRepresentation() };
433 else if( xValues
.is())
435 aResult
= { xValues
->getSourceRangeRepresentation() };
441 OUString
DataSourceHelper::getRangeFromValues(
442 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
447 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues() );
449 aResult
= xValues
->getSourceRangeRepresentation();
454 Sequence
< OUString
> DataSourceHelper::getRangesFromDataSource( const Reference
< data::XDataSource
> & xSource
)
456 std::vector
< OUString
> aResult
;
459 const Sequence
< Reference
< data::XLabeledDataSequence
> > aLSeqSeq( xSource
->getDataSequences());
460 for( Reference
< data::XLabeledDataSequence
> const & labeledData
: aLSeqSeq
)
462 Reference
< data::XDataSequence
> xLabel( labeledData
->getLabel());
463 Reference
< data::XDataSequence
> xValues( labeledData
->getValues());
466 aResult
.push_back( xLabel
->getSourceRangeRepresentation());
468 aResult
.push_back( xValues
->getSourceRangeRepresentation());
471 return comphelper::containerToSequence( aResult
);
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */