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>
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 uno::Sequence
< uno::Reference
< data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
70 for( sal_Int32 i
=0; i
<aDataSequences
.getLength(); ++i
)
71 lcl_addRanges( rOutResult
, aDataSequences
[i
] );
75 void lcl_addErrorBarRanges(
76 std::vector
< OUString
> & rOutResult
,
77 const uno::Reference
< XDataSeries
> & xDataSeries
)
79 uno::Reference
< beans::XPropertySet
> xSeriesProp( xDataSeries
, uno::UNO_QUERY
);
80 if( !xSeriesProp
.is())
85 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
86 if( ( xSeriesProp
->getPropertyValue( CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
) &&
89 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
90 if( ( xErrorBarProp
->getPropertyValue( "ErrorBarStyle") >>= eStyle
) &&
91 eStyle
== css::chart::ErrorBarStyle::FROM_DATA
)
93 uno::Reference
< data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
94 if( xErrorBarDataSource
.is() )
95 lcl_addDataSourceRanges( rOutResult
, xErrorBarDataSource
);
99 if( ( xSeriesProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
) && xErrorBarProp
.is())
101 sal_Int32 eStyle
= css::chart::ErrorBarStyle::NONE
;
102 if( ( xErrorBarProp
->getPropertyValue("ErrorBarStyle") >>= eStyle
) &&
103 eStyle
== css::chart::ErrorBarStyle::FROM_DATA
)
105 uno::Reference
< data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
106 if( xErrorBarDataSource
.is() )
107 lcl_addDataSourceRanges( rOutResult
, xErrorBarDataSource
);
111 catch( const uno::Exception
& )
113 DBG_UNHANDLED_EXCEPTION("chart2");
117 } // anonymous namespace
119 Reference
< chart2::data::XDataSource
> DataSourceHelper::createDataSource(
120 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> >& rSequences
)
122 return new DataSource(rSequences
);
125 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence()
127 return new ::chart::CachedDataSequence();
130 Reference
< chart2::data::XDataSequence
> DataSourceHelper::createCachedDataSequence( const OUString
& rSingleText
)
132 return new ::chart::CachedDataSequence( rSingleText
);
135 Reference
< chart2::data::XLabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
136 const Reference
< chart2::data::XDataSequence
>& xValues
,
137 const Reference
< chart2::data::XDataSequence
>& xLabels
)
139 return new ::chart::LabeledDataSequence( xValues
, xLabels
);
142 Reference
< chart2::data::XLabeledDataSequence
> DataSourceHelper::createLabeledDataSequence(
143 const Reference
< chart2::data::XDataSequence
>& xValues
)
145 return new ::chart::LabeledDataSequence( xValues
);
148 Reference
< chart2::data::XLabeledDataSequence
> DataSourceHelper::createLabeledDataSequence()
150 return new ::chart::LabeledDataSequence
;
153 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
154 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
156 css::chart::ChartDataRowSource eRowSource
= css::chart::ChartDataRowSource_ROWS
;
158 eRowSource
= css::chart::ChartDataRowSource_COLUMNS
;
160 uno::Sequence
< beans::PropertyValue
> aArguments(3);
161 aArguments
[0] = beans::PropertyValue( "DataRowSource"
162 , -1, uno::Any( eRowSource
)
163 , beans::PropertyState_DIRECT_VALUE
);
164 aArguments
[1] = beans::PropertyValue( "FirstCellAsLabel"
165 , -1, uno::Any( bFirstCellAsLabel
)
166 , beans::PropertyState_DIRECT_VALUE
);
167 aArguments
[2] = beans::PropertyValue( "HasCategories"
168 , -1, uno::Any( bHasCategories
)
169 , beans::PropertyState_DIRECT_VALUE
);
174 uno::Sequence
< beans::PropertyValue
> DataSourceHelper::createArguments(
175 const OUString
& rRangeRepresentation
,
176 const uno::Sequence
< sal_Int32
>& rSequenceMapping
,
177 bool bUseColumns
, bool bFirstCellAsLabel
, bool bHasCategories
)
179 uno::Sequence
< beans::PropertyValue
> aArguments( createArguments( bUseColumns
, bFirstCellAsLabel
, bHasCategories
));
180 aArguments
.realloc( aArguments
.getLength() + 1 );
181 aArguments
[aArguments
.getLength() - 1] =
182 beans::PropertyValue( "CellRangeRepresentation"
183 , -1, uno::Any( rRangeRepresentation
)
184 , beans::PropertyState_DIRECT_VALUE
);
185 if( rSequenceMapping
.hasElements() )
187 aArguments
.realloc( aArguments
.getLength() + 1 );
188 aArguments
[aArguments
.getLength() - 1] =
189 beans::PropertyValue( "SequenceMapping"
190 , -1, uno::Any( rSequenceMapping
)
191 , beans::PropertyState_DIRECT_VALUE
);
196 void DataSourceHelper::readArguments( const uno::Sequence
< beans::PropertyValue
>& rArguments
197 , OUString
& rRangeRepresentation
, uno::Sequence
< sal_Int32
>& rSequenceMapping
198 , bool& bUseColumns
, bool& bFirstCellAsLabel
, bool& bHasCategories
)
200 for(const beans::PropertyValue
& rProperty
: rArguments
)
202 if ( rProperty
.Name
== "DataRowSource" )
204 css::chart::ChartDataRowSource eRowSource
;
205 if( rProperty
.Value
>>= eRowSource
)
206 bUseColumns
= (eRowSource
==css::chart::ChartDataRowSource_COLUMNS
);
208 else if ( rProperty
.Name
== "FirstCellAsLabel" )
210 rProperty
.Value
>>= bFirstCellAsLabel
;
212 else if ( rProperty
.Name
== "HasCategories" )
214 rProperty
.Value
>>= bHasCategories
;
216 else if ( rProperty
.Name
== "CellRangeRepresentation" )
218 rProperty
.Value
>>= rRangeRepresentation
;
220 else if ( rProperty
.Name
== "SequenceMapping" )
222 rProperty
.Value
>>= rSequenceMapping
;
227 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::pressUsedDataIntoRectangularFormat(
228 const uno::Reference
< chart2::XChartDocument
>& xChartDoc
)
230 std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aResultVector
;
232 //categories are always the first sequence
233 Reference
< chart2::XDiagram
> xDiagram( xChartDoc
->getFirstDiagram());
235 Reference
< chart2::data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
236 if( xCategories
.is() )
237 aResultVector
.push_back( xCategories
);
239 std::vector
< Reference
< chart2::XDataSeries
> > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram
) );
240 uno::Reference
< chart2::data::XDataSource
> xSeriesSource(
241 DataSeriesHelper::getDataSource( comphelper::containerToSequence(aSeriesVector
) ) );
242 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aDataSequences( xSeriesSource
->getDataSequences() );
244 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
245 Reference
< chart2::data::XLabeledDataSequence
> xXValues(
246 DataSeriesHelper::getDataSequenceByRole( xSeriesSource
, "values-x" ) );
248 aResultVector
.push_back( xXValues
);
250 //add all other sequences now without x-values
251 for( sal_Int32 nN
=0; nN
<aDataSequences
.getLength(); nN
++ )
253 OUString aRole
= DataSeriesHelper::getRole(aDataSequences
[nN
]);
254 if( aRole
!= "values-x" )
255 aResultVector
.push_back( aDataSequences
[nN
] );
258 return new DataSource( comphelper::containerToSequence(aResultVector
) );
261 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges(
262 const uno::Reference
< chart2::XDiagram
> & xDiagram
)
264 std::vector
< OUString
> aResult
;
268 uno::Reference
< data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
269 if( xCategories
.is() )
270 lcl_addRanges( aResult
, xCategories
);
272 std::vector
< uno::Reference
< XDataSeries
> > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram
) );
273 for (auto const& series
: aSeriesVector
)
275 uno::Reference
< data::XDataSource
> xDataSource(series
, uno::UNO_QUERY
);
276 lcl_addDataSourceRanges( aResult
, xDataSource
);
277 lcl_addErrorBarRanges( aResult
, series
);
281 return comphelper::containerToSequence( aResult
);
284 uno::Sequence
< OUString
> DataSourceHelper::getUsedDataRanges( const uno::Reference
< frame::XModel
> & xChartModel
)
286 uno::Reference
< XDiagram
> xDiagram( ChartModelHelper::findDiagram( xChartModel
) );
287 return getUsedDataRanges( xDiagram
);
290 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::getUsedData(
291 const uno::Reference
< chart2::XChartDocument
>& xChartDoc
)
293 return pressUsedDataIntoRectangularFormat( xChartDoc
);
296 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::getUsedData(
297 const uno::Reference
< frame::XModel
>& xChartModel
)
299 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResult
;
301 uno::Reference
< XDiagram
> xDiagram( ChartModelHelper::findDiagram( xChartModel
) );
302 uno::Reference
< data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
303 if( xCategories
.is() )
304 aResult
.push_back( xCategories
);
306 std::vector
< uno::Reference
< XDataSeries
> > aSeriesVector( ChartModelHelper::getDataSeries( xChartModel
) );
307 for (auto const& series
: aSeriesVector
)
309 uno::Reference
< data::XDataSource
> xDataSource(series
, uno::UNO_QUERY
);
310 if( !xDataSource
.is() )
312 uno::Sequence
< uno::Reference
< data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
313 std::copy( aDataSequences
.begin(), aDataSequences
.end(),
314 std::back_inserter( aResult
));
317 return uno::Reference
< chart2::data::XDataSource
>(
318 new DataSource( comphelper::containerToSequence( aResult
)));
321 uno::Reference
< chart2::data::XDataSource
> DataSourceHelper::getUsedData(
324 std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aResult
;
326 uno::Reference
< XDiagram
> xDiagram( rModel
.getFirstDiagram() );
327 uno::Reference
< data::XLabeledDataSequence
> xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram
) );
328 if( xCategories
.is() )
329 aResult
.push_back( xCategories
);
331 std::vector
< uno::Reference
< XDataSeries
> > aSeriesVector( ChartModelHelper::getDataSeries( rModel
) );
332 for (auto const& series
: aSeriesVector
)
334 uno::Reference
< data::XDataSource
> xDataSource(series
, uno::UNO_QUERY
);
335 if( !xDataSource
.is() )
337 uno::Sequence
< uno::Reference
< data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
338 std::copy( aDataSequences
.begin(), aDataSequences
.end(),
339 std::back_inserter( aResult
));
342 return uno::Reference
< chart2::data::XDataSource
>(
343 new DataSource( comphelper::containerToSequence( aResult
)));
346 bool DataSourceHelper::detectRangeSegmentation(
347 const uno::Reference
<
348 frame::XModel
>& xChartModel
349 , OUString
& rOutRangeString
350 , css::uno::Sequence
< sal_Int32
>& rSequenceMapping
351 , bool& rOutUseColumns
352 , bool& rOutFirstCellAsLabel
353 , bool& rOutHasCategories
)
355 bool bSomethingDetected
= false;
357 uno::Reference
< XChartDocument
> xChartDocument( xChartModel
, uno::UNO_QUERY
);
358 if( !xChartDocument
.is() )
359 return bSomethingDetected
;
360 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
361 if( !xDataProvider
.is() )
362 return bSomethingDetected
;
366 DataSourceHelper::readArguments(
367 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
) ),
368 rOutRangeString
, rSequenceMapping
, rOutUseColumns
, rOutFirstCellAsLabel
, rOutHasCategories
);
369 bSomethingDetected
= !rOutRangeString
.isEmpty();
371 uno::Reference
< chart2::data::XLabeledDataSequence
> xCategories(
372 DiagramHelper::getCategoriesFromDiagram( xChartDocument
->getFirstDiagram() ));
373 rOutHasCategories
= xCategories
.is();
375 catch( uno::Exception
& )
377 DBG_UNHANDLED_EXCEPTION("chart2");
379 return bSomethingDetected
;
382 bool DataSourceHelper::allArgumentsForRectRangeDetected(
383 const uno::Reference
< chart2::XChartDocument
>& xChartDocument
)
385 bool bHasDataRowSource
= false;
386 bool bHasFirstCellAsLabel
= false;
387 bool bHasCellRangeRepresentation
= false;
389 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
390 if( !xDataProvider
.is() )
395 const uno::Sequence
< beans::PropertyValue
> aArguments(
396 xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
)));
397 for(const beans::PropertyValue
& rProperty
: aArguments
)
399 if ( rProperty
.Name
== "DataRowSource" )
402 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(
403 cppu::UnoType
<css::chart::ChartDataRowSource
>::get()));
405 else if ( rProperty
.Name
== "FirstCellAsLabel" )
407 bHasFirstCellAsLabel
=
408 (rProperty
.Value
.hasValue() && rProperty
.Value
.isExtractableTo(cppu::UnoType
<bool>::get()));
410 else if ( rProperty
.Name
== "CellRangeRepresentation" )
413 bHasCellRangeRepresentation
=
414 (rProperty
.Value
.hasValue() && (rProperty
.Value
>>= aRange
) && !aRange
.isEmpty());
418 catch( const uno::Exception
& )
420 DBG_UNHANDLED_EXCEPTION("chart2");
423 return (bHasCellRangeRepresentation
&& bHasDataRowSource
&& bHasFirstCellAsLabel
);
426 void DataSourceHelper::setRangeSegmentation(
427 const uno::Reference
< frame::XModel
>& xChartModel
428 , const css::uno::Sequence
< sal_Int32
>& rSequenceMapping
429 , bool bUseColumns
, bool bFirstCellAsLabel
, bool bUseCategories
)
431 uno::Reference
< XChartDocument
> xChartDocument( xChartModel
, uno::UNO_QUERY
);
432 if( !xChartDocument
.is() )
434 uno::Reference
< data::XDataProvider
> xDataProvider( xChartDocument
->getDataProvider() );
435 if( !xDataProvider
.is() )
437 uno::Reference
< XDiagram
> xDiagram( ChartModelHelper::findDiagram( xChartModel
) );
440 uno::Reference
< chart2::XChartTypeManager
> xChartTypeManager( xChartDocument
->getChartTypeManager() );
441 if( !xChartTypeManager
.is() )
443 uno::Reference
< lang::XMultiServiceFactory
> xTemplateFactory( xChartTypeManager
, uno::UNO_QUERY
);
444 if( !xTemplateFactory
.is() )
447 OUString aRangeString
;
449 uno::Sequence
< sal_Int32
> aDummy
;
450 readArguments( xDataProvider
->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument
)),
451 aRangeString
, aDummy
, bDummy
, bDummy
, bDummy
);
453 uno::Sequence
< beans::PropertyValue
> aArguments(
454 createArguments( aRangeString
, rSequenceMapping
, bUseColumns
, bFirstCellAsLabel
, bUseCategories
) );
456 uno::Reference
< chart2::data::XDataSource
> xDataSource( xDataProvider
->createDataSource(
458 if( !xDataSource
.is() )
461 ControllerLockGuardUNO
aCtrlLockGuard( xChartModel
);
462 xDiagram
->setDiagramData( xDataSource
, aArguments
);
465 Sequence
< OUString
> DataSourceHelper::getRangesFromLabeledDataSequence(
466 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
468 Sequence
< OUString
> aResult
;
471 Reference
< data::XDataSequence
> xLabel( xLSeq
->getLabel());
472 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues());
478 aResult
.realloc( 2 );
479 aResult
[0] = xLabel
->getSourceRangeRepresentation();
480 aResult
[1] = xValues
->getSourceRangeRepresentation();
484 aResult
.realloc( 1 );
485 aResult
[0] = xLabel
->getSourceRangeRepresentation();
488 else if( xValues
.is())
490 aResult
.realloc( 1 );
491 aResult
[0] = xValues
->getSourceRangeRepresentation();
497 OUString
DataSourceHelper::getRangeFromValues(
498 const Reference
< data::XLabeledDataSequence
> & xLSeq
)
503 Reference
< data::XDataSequence
> xValues( xLSeq
->getValues() );
505 aResult
= xValues
->getSourceRangeRepresentation();
510 Sequence
< OUString
> DataSourceHelper::getRangesFromDataSource( const Reference
< data::XDataSource
> & xSource
)
512 std::vector
< OUString
> aResult
;
515 Sequence
< Reference
< data::XLabeledDataSequence
> > aLSeqSeq( xSource
->getDataSequences());
516 for( sal_Int32 i
=0; i
<aLSeqSeq
.getLength(); ++i
)
518 Reference
< data::XDataSequence
> xLabel( aLSeqSeq
[i
]->getLabel());
519 Reference
< data::XDataSequence
> xValues( aLSeqSeq
[i
]->getValues());
522 aResult
.push_back( xLabel
->getSourceRangeRepresentation());
524 aResult
.push_back( xValues
->getSourceRangeRepresentation());
527 return comphelper::containerToSequence( aResult
);
532 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */