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 <DiagramHelper.hxx>
24 #include <DataSeriesHelper.hxx>
25 #include <DataSource.hxx>
26 #include <ControllerLockGuard.hxx>
27 #include <CachedDataSequence.hxx>
28 #include <LabeledDataSequence.hxx>
29 #include <unonames.hxx>
31 #include <com/sun/star/chart2/XChartDocument.hpp>
32 #include <com/sun/star/chart2/data/XDataSource.hpp>
33 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
35 #include <com/sun/star/chart/ChartDataRowSource.hpp>
36 #include <com/sun/star/chart/ErrorBarStyle.hpp>
37 #include <tools/diagnose_ex.h>
41 using namespace ::com::sun::star
;
42 using namespace ::com::sun::star::chart2
;
43 using ::com::sun::star::uno::Reference
;
44 using ::com::sun::star::uno::Sequence
;
48 void lcl_addRanges( std::vector
< OUString
> & rOutResult
,
49 const uno::Reference
< data::XLabeledDataSequence
> & xLabeledSeq
)
51 if( ! xLabeledSeq
.is())
53 uno::Reference
< data::XDataSequence
> xSeq( xLabeledSeq
->getLabel());
55 rOutResult
.push_back( xSeq
->getSourceRangeRepresentation());
56 xSeq
.set( xLabeledSeq
->getValues());
58 rOutResult
.push_back( xSeq
->getSourceRangeRepresentation());
61 void lcl_addDataSourceRanges(
62 std::vector
< OUString
> & rOutResult
,
63 const uno::Reference
< data::XDataSource
> & xDataSource
)
65 if( xDataSource
.is() )
67 const auto aDataSequences(xDataSource
->getDataSequences());
68 for (const auto& rDataSequence
: aDataSequences
)
69 lcl_addRanges(rOutResult
, rDataSequence
);
73 void lcl_addErrorBarRanges(
74 std::vector
< OUString
> & rOutResult
,
75 const uno::Reference
< XDataSeries
> & xDataSeries
)
77 uno::Reference
< beans::XPropertySet
> xSeriesProp( xDataSeries
, uno::UNO_QUERY
);
78 if( !xSeriesProp
.is())
83 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
84 if( ( xSeriesProp
->getPropertyValue( CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
) &&
87 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
88 if( ( xErrorBarProp
->getPropertyValue( "ErrorBarStyle") >>= 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( ( xSeriesProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
) && xErrorBarProp
.is())
99 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
100 if( ( xErrorBarProp
->getPropertyValue("ErrorBarStyle") >>= 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::XDataSource
> DataSourceHelper::createDataSource(
118 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> >& rSequences
)
120 return new DataSource(rSequences
);
123 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence()
125 return new ::chart::CachedDataSequence();
128 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence( const OUString
& rSingleText
)
130 return new ::chart::CachedDataSequence( rSingleText
);
133 Reference
< chart2::data::XLabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
134 const Reference
< chart2::data::XDataSequence
>& xValues
,
135 const Reference
< chart2::data::XDataSequence
>& xLabels
)
137 return new ::chart::LabeledDataSequence( xValues
, xLabels
);
140 Reference
< chart2::data::XLabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
141 const Reference
< chart2::data::XDataSequence
>& xValues
)
143 return new ::chart::LabeledDataSequence( xValues
);
146 Reference
< chart2::data::XLabeledDataSequence
> DataSourceHelper::createLabeledDataSequence()
148 return new ::chart::LabeledDataSequence
;
151 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
152 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
154 css::chart::ChartDataRowSource eRowSource
= css::chart::ChartDataRowSource_ROWS
;
156 eRowSource
= css::chart::ChartDataRowSource_COLUMNS
;
158 uno::Sequence
< beans::PropertyValue
> aArguments(3);
159 aArguments
[0] = beans::PropertyValue( "DataRowSource"
160 , -1, uno::Any( eRowSource
)
161 , beans::PropertyState_DIRECT_VALUE
);
162 aArguments
[1] = beans::PropertyValue( "FirstCellAsLabel"
163 , -1, uno::Any( bFirstCellAsLabel
)
164 , beans::PropertyState_DIRECT_VALUE
);
165 aArguments
[2] = beans::PropertyValue( "HasCategories"
166 , -1, uno::Any( bHasCategories
)
167 , beans::PropertyState_DIRECT_VALUE
);
172 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
173 const OUString
& rRangeRepresentation
,
174 const uno::Sequence
< sal_Int32
>& rSequenceMapping
,
175 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
177 uno::Sequence
< beans::PropertyValue
> aArguments( createArguments( bUseColumns
, bFirstCellAsLabel
, bHasCategories
));
178 aArguments
.realloc( aArguments
.getLength() + 1 );
179 aArguments
[aArguments
.getLength() - 1] =
180 beans::PropertyValue( "CellRangeRepresentation"
181 , -1, uno::Any( rRangeRepresentation
)
182 , beans::PropertyState_DIRECT_VALUE
);
183 if( rSequenceMapping
.hasElements() )
185 aArguments
.realloc( aArguments
.getLength() + 1 );
186 aArguments
[aArguments
.getLength() - 1] =
187 beans::PropertyValue( "SequenceMapping"
188 , -1, uno::Any( rSequenceMapping
)
189 , beans::PropertyState_DIRECT_VALUE
);
194 void DataSourceHelper::readArguments( const uno::Sequence
< beans::PropertyValue
>& rArguments
195 , OUString
& rRangeRepresentation
, uno::Sequence
< sal_Int32
>& rSequenceMapping
196 , bool& bUseColumns
, bool& bFirstCellAsLabel
, bool& bHasCategories
)
198 for(const beans::PropertyValue
& rProperty
: rArguments
)
200 if ( rProperty
.Name
== "DataRowSource" )
202 css::chart::ChartDataRowSource eRowSource
;
203 if( rProperty
.Value
>>= eRowSource
)
204 bUseColumns
= (eRowSource
==css::chart::ChartDataRowSource_COLUMNS
);
206 else if ( rProperty
.Name
== "FirstCellAsLabel" )
208 rProperty
.Value
>>= bFirstCellAsLabel
;
210 else if ( rProperty
.Name
== "HasCategories" )
212 rProperty
.Value
>>= bHasCategories
;
214 else if ( rProperty
.Name
== "CellRangeRepresentation" )
216 rProperty
.Value
>>= rRangeRepresentation
;
218 else if ( rProperty
.Name
== "SequenceMapping" )
220 rProperty
.Value
>>= rSequenceMapping
;
225 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::pressUsedDataIntoRectangularFormat(
226 const uno::Reference
< chart2::XChartDocument
>& xChartDoc
)
228 std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aResultVector
;
230 //categories are always the first sequence
231 Reference
< chart2::XDiagram
> xDiagram( xChartDoc
->getFirstDiagram());
233 Reference
< chart2::data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
234 if( xCategories
.is() )
235 aResultVector
.push_back( xCategories
);
237 std::vector
< Reference
< chart2::XDataSeries
> > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram
) );
238 uno::Reference
< chart2::data::XDataSource
> xSeriesSource(
239 DataSeriesHelper::getDataSource( comphelper::containerToSequence(aSeriesVector
) ) );
240 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aDataSequences( xSeriesSource
->getDataSequences() );
242 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
243 Reference
< chart2::data::XLabeledDataSequence
> xXValues(
244 DataSeriesHelper::getDataSequenceByRole( xSeriesSource
, "values-x" ) );
246 aResultVector
.push_back( xXValues
);
248 //add all other sequences now without x-values
249 for( Reference
< chart2::data::XLabeledDataSequence
> const & labeledData
: aDataSequences
)
251 OUString aRole
= DataSeriesHelper::getRole(labeledData
);
252 if( aRole
!= "values-x" )
253 aResultVector
.push_back( labeledData
);
256 return new DataSource( comphelper::containerToSequence(aResultVector
) );
259 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges(
260 const uno::Reference
< chart2::XDiagram
> & xDiagram
)
262 std::vector
< OUString
> aResult
;
266 uno::Reference
< data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
267 if( xCategories
.is() )
268 lcl_addRanges( aResult
, xCategories
);
270 std::vector
< uno::Reference
< XDataSeries
> > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram
) );
271 for (auto const& series
: aSeriesVector
)
273 uno::Reference
< data::XDataSource
> xDataSource(series
, uno::UNO_QUERY
);
274 lcl_addDataSourceRanges( aResult
, xDataSource
);
275 lcl_addErrorBarRanges( aResult
, series
);
279 return comphelper::containerToSequence( aResult
);
282 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges( const uno::Reference
< frame::XModel
> & xChartModel
)
284 uno::Reference
< XDiagram
> xDiagram( ChartModelHelper::findDiagram( xChartModel
) );
285 return getUsedDataRanges( xDiagram
);
288 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::getUsedData(
289 const uno::Reference
< chart2::XChartDocument
>& xChartDoc
)
291 return pressUsedDataIntoRectangularFormat( xChartDoc
);
294 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::getUsedData(
295 const uno::Reference
< frame::XModel
>& xChartModel
)
297 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResult
;
299 uno::Reference
< XDiagram
> xDiagram( ChartModelHelper::findDiagram( xChartModel
) );
300 uno::Reference
< data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
301 if( xCategories
.is() )
302 aResult
.push_back( xCategories
);
304 std::vector
< uno::Reference
< XDataSeries
> > aSeriesVector( ChartModelHelper::getDataSeries( xChartModel
) );
305 for (auto const& series
: aSeriesVector
)
307 uno::Reference
< data::XDataSource
> xDataSource(series
, uno::UNO_QUERY
);
308 if( !xDataSource
.is() )
310 uno::Sequence
< uno::Reference
< data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
311 aResult
.insert( aResult
.end(), aDataSequences
.begin(), aDataSequences
.end() );
314 return uno::Reference
< chart2::data::XDataSource
>(
315 new DataSource( comphelper::containerToSequence( aResult
)));
318 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::getUsedData(
321 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResult
;
323 uno::Reference
< XDiagram
> xDiagram( rModel
.getFirstDiagram() );
324 uno::Reference
< data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
325 if( xCategories
.is() )
326 aResult
.push_back( xCategories
);
328 std::vector
< uno::Reference
< XDataSeries
> > aSeriesVector( ChartModelHelper::getDataSeries( rModel
) );
329 for (auto const& series
: aSeriesVector
)
331 uno::Reference
< data::XDataSource
> xDataSource(series
, uno::UNO_QUERY
);
332 if( !xDataSource
.is() )
334 uno::Sequence
< uno::Reference
< data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
335 aResult
.insert( aResult
.end(), aDataSequences
.begin(), aDataSequences
.end() );
338 return uno::Reference
< chart2::data::XDataSource
>(
339 new DataSource( comphelper::containerToSequence( aResult
)));
342 bool DataSourceHelper::detectRangeSegmentation(
343 const uno::Reference
<
344 frame::XModel
>& xChartModel
345 , OUString
& rOutRangeString
346 , css::uno::Sequence
< sal_Int32
>& rSequenceMapping
347 , bool& rOutUseColumns
348 , bool& rOutFirstCellAsLabel
349 , bool& rOutHasCategories
)
351 bool bSomethingDetected
= false;
353 uno::Reference
< XChartDocument
> xChartDocument( xChartModel
, uno::UNO_QUERY
);
354 if( !xChartDocument
.is() )
355 return bSomethingDetected
;
356 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
357 if( !xDataProvider
.is() )
358 return bSomethingDetected
;
362 DataSourceHelper::readArguments(
363 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
) ),
364 rOutRangeString
, rSequenceMapping
, rOutUseColumns
, rOutFirstCellAsLabel
, rOutHasCategories
);
365 bSomethingDetected
= !rOutRangeString
.isEmpty();
367 uno::Reference
< chart2::data::XLabeledDataSequence
> xCategories(
368 DiagramHelper::getCategoriesFromDiagram( xChartDocument
->getFirstDiagram() ));
369 rOutHasCategories
= xCategories
.is();
371 catch( uno::Exception
& )
373 DBG_UNHANDLED_EXCEPTION("chart2");
375 return bSomethingDetected
;
378 bool DataSourceHelper::allArgumentsForRectRangeDetected(
379 const uno::Reference
< chart2::XChartDocument
>& xChartDocument
)
381 bool bHasDataRowSource
= false;
382 bool bHasFirstCellAsLabel
= false;
383 bool bHasCellRangeRepresentation
= false;
385 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
386 if( !xDataProvider
.is() )
391 const uno::Sequence
< beans::PropertyValue
> aArguments(
392 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
)));
393 for(const beans::PropertyValue
& rProperty
: aArguments
)
395 if ( rProperty
.Name
== "DataRowSource" )
398 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(
399 cppu::UnoType
<css::chart::ChartDataRowSource
>::get()));
401 else if ( rProperty
.Name
== "FirstCellAsLabel" )
403 bHasFirstCellAsLabel
=
404 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(cppu::UnoType
<bool>::get()));
406 else if ( rProperty
.Name
== "CellRangeRepresentation" )
409 bHasCellRangeRepresentation
=
410 (rProperty
.Value
.hasValue() && (rProperty
.Value
>>= aRange
) && !aRange
.isEmpty());
414 catch( const uno::Exception
& )
416 DBG_UNHANDLED_EXCEPTION("chart2");
419 return (bHasCellRangeRepresentation
&& bHasDataRowSource
&& bHasFirstCellAsLabel
);
422 void DataSourceHelper::setRangeSegmentation(
423 const uno::Reference
< frame::XModel
>& xChartModel
424 , const css::uno::Sequence
< sal_Int32
>& rSequenceMapping
425 , bool bUseColumns
, bool bFirstCellAsLabel
, bool bUseCategories
)
427 uno::Reference
< XChartDocument
> xChartDocument( xChartModel
, uno::UNO_QUERY
);
428 if( !xChartDocument
.is() )
430 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
431 if( !xDataProvider
.is() )
433 uno::Reference
< XDiagram
> xDiagram( ChartModelHelper::findDiagram( xChartModel
) );
436 uno::Reference
< chart2::XChartTypeManager
> xChartTypeManager( xChartDocument
->getChartTypeManager() );
437 if( !xChartTypeManager
.is() )
439 uno::Reference
< lang::XMultiServiceFactory
> xTemplateFactory( xChartTypeManager
, uno::UNO_QUERY
);
440 if( !xTemplateFactory
.is() )
443 OUString aRangeString
;
445 uno::Sequence
< sal_Int32
> aDummy
;
446 readArguments( xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
)),
447 aRangeString
, aDummy
, bDummy
, bDummy
, bDummy
);
449 uno::Sequence
< beans::PropertyValue
> aArguments(
450 createArguments( aRangeString
, rSequenceMapping
, bUseColumns
, bFirstCellAsLabel
, bUseCategories
) );
452 uno::Reference
< chart2::data::XDataSource
> xDataSource( xDataProvider
->createDataSource(
454 if( !xDataSource
.is() )
457 ControllerLockGuardUNO
aCtrlLockGuard( xChartModel
);
458 xDiagram
->setDiagramData( xDataSource
, aArguments
);
461 Sequence
< OUString
> DataSourceHelper::getRangesFromLabeledDataSequence(
462 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
464 Sequence
< OUString
> aResult
;
467 Reference
< data::XDataSequence
> xLabel( xLSeq
->getLabel());
468 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues());
474 aResult
.realloc( 2 );
475 aResult
[0] = xLabel
->getSourceRangeRepresentation();
476 aResult
[1] = xValues
->getSourceRangeRepresentation();
480 aResult
.realloc( 1 );
481 aResult
[0] = xLabel
->getSourceRangeRepresentation();
484 else if( xValues
.is())
486 aResult
.realloc( 1 );
487 aResult
[0] = xValues
->getSourceRangeRepresentation();
493 OUString
DataSourceHelper::getRangeFromValues(
494 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
499 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues() );
501 aResult
= xValues
->getSourceRangeRepresentation();
506 Sequence
< OUString
> DataSourceHelper::getRangesFromDataSource( const Reference
< data::XDataSource
> & xSource
)
508 std::vector
< OUString
> aResult
;
511 const Sequence
< Reference
< data::XLabeledDataSequence
> > aLSeqSeq( xSource
->getDataSequences());
512 for( Reference
< data::XLabeledDataSequence
> const & labeledData
: aLSeqSeq
)
514 Reference
< data::XDataSequence
> xLabel( labeledData
->getLabel());
515 Reference
< data::XDataSequence
> xValues( labeledData
->getValues());
518 aResult
.push_back( xLabel
->getSourceRangeRepresentation());
520 aResult
.push_back( xValues
->getSourceRangeRepresentation());
523 return comphelper::containerToSequence( aResult
);
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */