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 <DiagramHelper.hxx>
25 #include <Diagram.hxx>
26 #include <DataSeries.hxx>
27 #include <DataSeriesHelper.hxx>
28 #include <DataSource.hxx>
29 #include <ControllerLockGuard.hxx>
30 #include <CachedDataSequence.hxx>
31 #include <LabeledDataSequence.hxx>
32 #include <unonames.hxx>
34 #include <com/sun/star/chart2/data/XDataSource.hpp>
35 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
37 #include <com/sun/star/chart/ChartDataRowSource.hpp>
38 #include <com/sun/star/chart/ErrorBarStyle.hpp>
39 #include <comphelper/diagnose_ex.hxx>
43 using namespace ::com::sun::star
;
44 using namespace ::com::sun::star::chart2
;
45 using ::com::sun::star::uno::Reference
;
46 using ::com::sun::star::uno::Sequence
;
50 void lcl_addRanges( std::vector
< OUString
> & rOutResult
,
51 const uno::Reference
< data::XLabeledDataSequence
> & xLabeledSeq
)
53 if( ! xLabeledSeq
.is())
55 uno::Reference
< data::XDataSequence
> xSeq( xLabeledSeq
->getLabel());
57 rOutResult
.push_back( xSeq
->getSourceRangeRepresentation());
58 xSeq
.set( xLabeledSeq
->getValues());
60 rOutResult
.push_back( xSeq
->getSourceRangeRepresentation());
63 void lcl_addDataSourceRanges(
64 std::vector
< OUString
> & rOutResult
,
65 const uno::Reference
< data::XDataSource
> & xDataSource
)
67 if( xDataSource
.is() )
69 const auto aDataSequences(xDataSource
->getDataSequences());
70 for (const auto& rDataSequence
: aDataSequences
)
71 lcl_addRanges(rOutResult
, rDataSequence
);
75 void lcl_addErrorBarRanges(
76 std::vector
< OUString
> & rOutResult
,
77 const rtl::Reference
< DataSeries
> & xDataSeries
)
79 if( !xDataSeries
.is())
84 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
85 if( ( xDataSeries
->getPropertyValue( CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
) &&
88 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
89 if( ( xErrorBarProp
->getPropertyValue( "ErrorBarStyle") >>= eStyle
) &&
90 eStyle
== css::chart::ErrorBarStyle::FROM_DATA
)
92 uno::Reference
< data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
93 if( xErrorBarDataSource
.is() )
94 lcl_addDataSourceRanges( rOutResult
, xErrorBarDataSource
);
98 if( ( xDataSeries
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
) && xErrorBarProp
.is())
100 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
101 if( ( xErrorBarProp
->getPropertyValue("ErrorBarStyle") >>= eStyle
) &&
102 eStyle
== css::chart::ErrorBarStyle::FROM_DATA
)
104 uno::Reference
< data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
105 if( xErrorBarDataSource
.is() )
106 lcl_addDataSourceRanges( rOutResult
, xErrorBarDataSource
);
110 catch( const uno::Exception
& )
112 DBG_UNHANDLED_EXCEPTION("chart2");
116 } // anonymous namespace
118 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence()
120 return new ::chart::CachedDataSequence();
123 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence( const OUString
& rSingleText
)
125 return new ::chart::CachedDataSequence( rSingleText
);
128 rtl::Reference
< LabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
129 const Reference
< chart2::data::XDataSequence
>& xValues
,
130 const Reference
< chart2::data::XDataSequence
>& xLabels
)
132 return new ::chart::LabeledDataSequence( xValues
, xLabels
);
135 rtl::Reference
< LabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
136 const Reference
< chart2::data::XDataSequence
>& xValues
)
138 return new ::chart::LabeledDataSequence( xValues
);
141 rtl::Reference
< LabeledDataSequence
> DataSourceHelper::createLabeledDataSequence()
143 return new ::chart::LabeledDataSequence
;
146 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
147 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
149 css::chart::ChartDataRowSource eRowSource
= css::chart::ChartDataRowSource_ROWS
;
151 eRowSource
= css::chart::ChartDataRowSource_COLUMNS
;
155 { "DataRowSource", -1, uno::Any( eRowSource
), beans::PropertyState_DIRECT_VALUE
},
156 { "FirstCellAsLabel", -1, uno::Any( bFirstCellAsLabel
), beans::PropertyState_DIRECT_VALUE
},
157 { "HasCategories", -1, uno::Any( bHasCategories
), beans::PropertyState_DIRECT_VALUE
}
161 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
162 const OUString
& rRangeRepresentation
,
163 const uno::Sequence
< sal_Int32
>& rSequenceMapping
,
164 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
166 uno::Sequence
< beans::PropertyValue
> aArguments( createArguments( bUseColumns
, bFirstCellAsLabel
, bHasCategories
));
167 aArguments
.realloc( aArguments
.getLength() + 1 );
168 aArguments
.getArray()[aArguments
.getLength() - 1] =
169 beans::PropertyValue( "CellRangeRepresentation"
170 , -1, uno::Any( rRangeRepresentation
)
171 , beans::PropertyState_DIRECT_VALUE
);
172 if( rSequenceMapping
.hasElements() )
174 aArguments
.realloc( aArguments
.getLength() + 1 );
175 aArguments
.getArray()[aArguments
.getLength() - 1] =
176 beans::PropertyValue( "SequenceMapping"
177 , -1, uno::Any( rSequenceMapping
)
178 , beans::PropertyState_DIRECT_VALUE
);
183 void DataSourceHelper::readArguments( const uno::Sequence
< beans::PropertyValue
>& rArguments
184 , OUString
& rRangeRepresentation
, uno::Sequence
< sal_Int32
>& rSequenceMapping
185 , bool& bUseColumns
, bool& bFirstCellAsLabel
, bool& bHasCategories
)
187 for(const beans::PropertyValue
& rProperty
: rArguments
)
189 if ( rProperty
.Name
== "DataRowSource" )
191 css::chart::ChartDataRowSource eRowSource
;
192 if( rProperty
.Value
>>= eRowSource
)
193 bUseColumns
= (eRowSource
==css::chart::ChartDataRowSource_COLUMNS
);
195 else if ( rProperty
.Name
== "FirstCellAsLabel" )
197 rProperty
.Value
>>= bFirstCellAsLabel
;
199 else if ( rProperty
.Name
== "HasCategories" )
201 rProperty
.Value
>>= bHasCategories
;
203 else if ( rProperty
.Name
== "CellRangeRepresentation" )
205 rProperty
.Value
>>= rRangeRepresentation
;
207 else if ( rProperty
.Name
== "SequenceMapping" )
209 rProperty
.Value
>>= rSequenceMapping
;
214 rtl::Reference
< DataSource
> DataSourceHelper::pressUsedDataIntoRectangularFormat(
215 const rtl::Reference
< ChartModel
>& xChartDoc
)
217 std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aResultVector
;
219 //categories are always the first sequence
220 rtl::Reference
< Diagram
> xDiagram( xChartDoc
->getFirstChartDiagram());
222 Reference
< chart2::data::XLabeledDataSequence
> xCategories
;
224 xCategories
= xDiagram
->getCategories();
225 if( xCategories
.is() )
226 aResultVector
.push_back( xCategories
);
228 std::vector
< rtl::Reference
< DataSeries
> > aSeriesVector
;
230 aSeriesVector
= xDiagram
->getDataSeries();
231 uno::Reference
< chart2::data::XDataSource
> xSeriesSource
=
232 DataSeriesHelper::getDataSource( aSeriesVector
);
233 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aDataSequences( xSeriesSource
->getDataSequences() );
235 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
236 Reference
< chart2::data::XLabeledDataSequence
> xXValues(
237 DataSeriesHelper::getDataSequenceByRole( xSeriesSource
, "values-x" ) );
239 aResultVector
.push_back( xXValues
);
241 //add all other sequences now without x-values
242 for( Reference
< chart2::data::XLabeledDataSequence
> const & labeledData
: aDataSequences
)
244 OUString aRole
= DataSeriesHelper::getRole(labeledData
);
245 if( aRole
!= "values-x" )
246 aResultVector
.push_back( labeledData
);
249 return new DataSource( aResultVector
);
252 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges(
253 const rtl::Reference
< Diagram
> & xDiagram
)
255 std::vector
< OUString
> aResult
;
259 uno::Reference
< data::XLabeledDataSequence
> xCategories( xDiagram
->getCategories() );
260 if( xCategories
.is() )
261 lcl_addRanges( aResult
, xCategories
);
263 std::vector
< rtl::Reference
< DataSeries
> > aSeriesVector( xDiagram
->getDataSeries() );
264 for (auto const& series
: aSeriesVector
)
266 lcl_addDataSourceRanges( aResult
, series
);
267 lcl_addErrorBarRanges( aResult
, series
);
271 return comphelper::containerToSequence( aResult
);
274 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges( const rtl::Reference
<::chart::ChartModel
> & xChartModel
)
276 rtl::Reference
< Diagram
> xDiagram( xChartModel
->getFirstChartDiagram() );
277 return getUsedDataRanges( xDiagram
);
280 rtl::Reference
< DataSource
> DataSourceHelper::getUsedData(
283 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResult
;
285 rtl::Reference
< Diagram
> xDiagram
= rModel
.getFirstChartDiagram();
286 uno::Reference
< chart2::data::XLabeledDataSequence
> xCategories( xDiagram
->getCategories() );
287 if( xCategories
.is() )
288 aResult
.push_back( xCategories
);
290 std::vector
< rtl::Reference
< DataSeries
> > aSeriesVector
= ChartModelHelper::getDataSeries( &rModel
);
291 for (auto const& series
: aSeriesVector
)
293 const std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > & aDataSequences( series
->getDataSequences2() );
294 aResult
.insert( aResult
.end(), aDataSequences
.begin(), aDataSequences
.end() );
297 return new DataSource( aResult
);
300 bool DataSourceHelper::detectRangeSegmentation(
301 const rtl::Reference
<::chart::ChartModel
>& xChartModel
302 , OUString
& rOutRangeString
303 , css::uno::Sequence
< sal_Int32
>& rSequenceMapping
304 , bool& rOutUseColumns
305 , bool& rOutFirstCellAsLabel
306 , bool& rOutHasCategories
)
308 bool bSomethingDetected
= false;
310 if( !xChartModel
.is() )
311 return bSomethingDetected
;
312 uno::Reference
< data::XDataProvider
> xDataProvider( xChartModel
->getDataProvider() );
313 if( !xDataProvider
.is() )
314 return bSomethingDetected
;
318 DataSourceHelper::readArguments(
319 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartModel
) ),
320 rOutRangeString
, rSequenceMapping
, rOutUseColumns
, rOutFirstCellAsLabel
, rOutHasCategories
);
321 bSomethingDetected
= !rOutRangeString
.isEmpty();
323 rtl::Reference
<Diagram
> xDiagram
= xChartModel
->getFirstChartDiagram();
324 uno::Reference
< chart2::data::XLabeledDataSequence
> xCategories
;
326 xCategories
= xDiagram
->getCategories();
327 rOutHasCategories
= xCategories
.is();
329 catch( uno::Exception
& )
331 DBG_UNHANDLED_EXCEPTION("chart2");
333 return bSomethingDetected
;
336 bool DataSourceHelper::allArgumentsForRectRangeDetected(
337 const rtl::Reference
<::chart::ChartModel
>& xChartDocument
)
339 bool bHasDataRowSource
= false;
340 bool bHasFirstCellAsLabel
= false;
341 bool bHasCellRangeRepresentation
= false;
343 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
344 if( !xDataProvider
.is() )
349 const uno::Sequence
< beans::PropertyValue
> aArguments(
350 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
)));
351 for(const beans::PropertyValue
& rProperty
: aArguments
)
353 if ( rProperty
.Name
== "DataRowSource" )
356 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(
357 cppu::UnoType
<css::chart::ChartDataRowSource
>::get()));
359 else if ( rProperty
.Name
== "FirstCellAsLabel" )
361 bHasFirstCellAsLabel
=
362 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(cppu::UnoType
<bool>::get()));
364 else if ( rProperty
.Name
== "CellRangeRepresentation" )
367 bHasCellRangeRepresentation
=
368 (rProperty
.Value
.hasValue() && (rProperty
.Value
>>= aRange
) && !aRange
.isEmpty());
372 catch( const uno::Exception
& )
374 DBG_UNHANDLED_EXCEPTION("chart2");
377 return (bHasCellRangeRepresentation
&& bHasDataRowSource
&& bHasFirstCellAsLabel
);
380 void DataSourceHelper::setRangeSegmentation(
381 const rtl::Reference
<::chart::ChartModel
>& xChartModel
382 , const css::uno::Sequence
< sal_Int32
>& rSequenceMapping
383 , bool bUseColumns
, bool bFirstCellAsLabel
, bool bUseCategories
)
385 uno::Reference
< data::XDataProvider
> xDataProvider( xChartModel
->getDataProvider() );
386 if( !xDataProvider
.is() )
388 rtl::Reference
< Diagram
> xDiagram( xChartModel
->getFirstChartDiagram() );
391 rtl::Reference
< ::chart::ChartTypeManager
> xChartTypeManager
= xChartModel
->getTypeManager();
392 if( !xChartTypeManager
.is() )
395 OUString aRangeString
;
397 uno::Sequence
< sal_Int32
> aDummy
;
398 readArguments( xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartModel
)),
399 aRangeString
, aDummy
, bDummy
, bDummy
, bDummy
);
401 uno::Sequence
< beans::PropertyValue
> aArguments(
402 createArguments( aRangeString
, rSequenceMapping
, bUseColumns
, bFirstCellAsLabel
, bUseCategories
) );
404 uno::Reference
< chart2::data::XDataSource
> xDataSource( xDataProvider
->createDataSource(
406 if( !xDataSource
.is() )
409 ControllerLockGuardUNO
aCtrlLockGuard( xChartModel
);
410 xDiagram
->setDiagramData( xDataSource
, aArguments
);
413 Sequence
< OUString
> DataSourceHelper::getRangesFromLabeledDataSequence(
414 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
416 Sequence
< OUString
> aResult
;
419 Reference
< data::XDataSequence
> xLabel( xLSeq
->getLabel());
420 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues());
426 aResult
= { xLabel
->getSourceRangeRepresentation(),
427 xValues
->getSourceRangeRepresentation() };
431 aResult
= { xLabel
->getSourceRangeRepresentation() };
434 else if( xValues
.is())
436 aResult
= { xValues
->getSourceRangeRepresentation() };
442 OUString
DataSourceHelper::getRangeFromValues(
443 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
448 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues() );
450 aResult
= xValues
->getSourceRangeRepresentation();
455 Sequence
< OUString
> DataSourceHelper::getRangesFromDataSource( const Reference
< data::XDataSource
> & xSource
)
457 std::vector
< OUString
> aResult
;
460 const Sequence
< Reference
< data::XLabeledDataSequence
> > aLSeqSeq( xSource
->getDataSequences());
461 for( Reference
< data::XLabeledDataSequence
> const & labeledData
: aLSeqSeq
)
463 Reference
< data::XDataSequence
> xLabel( labeledData
->getLabel());
464 Reference
< data::XDataSequence
> xValues( labeledData
->getValues());
467 aResult
.push_back( xLabel
->getSourceRangeRepresentation());
469 aResult
.push_back( xValues
->getSourceRangeRepresentation());
472 return comphelper::containerToSequence( aResult
);
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */