cid#1607171 Data race condition
[LibreOffice.git] / chart2 / source / model / template / DataInterpreter.cxx
blob07febd7a63faf474c8c6eeb2a472dc393aef3e2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <DataInterpreter.hxx>
21 #include <DataSeries.hxx>
22 #include <DataSource.hxx>
23 #include <DataSeriesHelper.hxx>
24 #include <CommonConverters.hxx>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <cppuhelper/supportsservice.hxx>
27 #include <comphelper/diagnose_ex.hxx>
29 #include <algorithm>
30 #include <cstddef>
32 using namespace ::com::sun::star;
33 using namespace ::com::sun::star::chart2;
35 using ::com::sun::star::uno::Reference;
36 using ::com::sun::star::uno::Sequence;
38 #ifdef DEBUG_CHART2_TEMPLATE
39 namespace
41 void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource );
43 #endif
45 namespace chart
48 DataInterpreter::DataInterpreter()
51 DataInterpreter::~DataInterpreter()
54 // ____ XDataInterpreter ____
55 InterpretedData DataInterpreter::interpretDataSource(
56 const Reference< data::XDataSource >& xSource,
57 const Sequence< beans::PropertyValue >& aArguments,
58 const std::vector< rtl::Reference< DataSeries > >& aSeriesToReUse )
60 if( ! xSource.is())
61 return InterpretedData();
63 #ifdef DEBUG_CHART2_TEMPLATE
64 lcl_ShowDataSource( xSource );
65 #endif
67 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = getDataSequences(xSource);
69 uno::Reference< chart2::data::XLabeledDataSequence > xCategories;
70 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequencesVec;
72 // check if we should use categories
74 bool bHasCategories( HasCategories( aArguments, aData ));
76 // parse data
77 bool bCategoriesUsed = false;
78 for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aData )
80 try
82 if( bHasCategories && ! bCategoriesUsed )
84 xCategories = labeledData;
85 if( xCategories.is())
86 SetRole( xCategories->getValues(), u"categories"_ustr);
87 bCategoriesUsed = true;
89 else
91 aSequencesVec.push_back( labeledData );
92 if( labeledData.is())
93 SetRole( labeledData->getValues(), u"values-y"_ustr);
96 catch( const uno::Exception & )
98 DBG_UNHANDLED_EXCEPTION("chart2");
102 // create DataSeries
103 std::size_t nSeriesIndex = 0;
104 std::vector< rtl::Reference< DataSeries > > aSeriesVec;
105 aSeriesVec.reserve( aSequencesVec.size());
107 for (auto const& elem : aSequencesVec)
109 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewData { elem };
110 rtl::Reference< DataSeries > xSeries;
111 if( nSeriesIndex < aSeriesToReUse.size())
112 xSeries = aSeriesToReUse[nSeriesIndex];
113 else
114 xSeries = new DataSeries;
115 assert( xSeries.is() );
116 xSeries->setData( aNewData );
118 aSeriesVec.push_back( xSeries );
119 ++nSeriesIndex;
122 return { { std::move(aSeriesVec) }, xCategories };
125 InterpretedData DataInterpreter::reinterpretDataSeries(
126 const InterpretedData& aInterpretedData )
128 InterpretedData aResult( aInterpretedData );
130 sal_Int32 i=0;
131 std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
132 const sal_Int32 nCount = aSeries.size();
133 for( ; i<nCount; ++i )
137 std::vector< uno::Reference< data::XLabeledDataSequence > > aNewSequences;
139 // values-y
140 uno::Reference< data::XLabeledDataSequence > xValuesY =
141 DataSeriesHelper::getDataSequenceByRole( aSeries[i], u"values-y"_ustr );
142 // re-use values-... as values-y
143 if( ! xValuesY.is())
145 xValuesY =
146 DataSeriesHelper::getDataSequenceByRole( aSeries[i], u"values"_ustr, true );
147 if( xValuesY.is())
148 SetRole( xValuesY->getValues(), u"values-y"_ustr);
150 if( xValuesY.is())
152 aNewSequences = { xValuesY };
155 const std::vector< uno::Reference< data::XLabeledDataSequence > > & aSeqs = aSeries[i]->getDataSequences2();
156 if( aSeqs.size() != aNewSequences.size() )
158 #ifdef DEBUG_CHART2_TEMPLATE
159 sal_Int32 j=0;
160 for( ; j<aSeqs.(); ++j )
162 assert( aSeqs[j] == xValuesY && "All sequences should be used" );
164 #endif
165 aSeries[i]->setData( aNewSequences );
168 catch( const uno::Exception & )
170 DBG_UNHANDLED_EXCEPTION("chart2");
174 return aResult;
177 // criterion: all series must have exactly one data::XLabeledDataSequence
178 bool DataInterpreter::isDataCompatible(
179 const InterpretedData& aInterpretedData )
181 const std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
182 for( rtl::Reference< DataSeries > const & i : aSeries )
186 if( i->getDataSequences2().size() != 1 )
187 return false;
189 catch( const uno::Exception & )
191 DBG_UNHANDLED_EXCEPTION("chart2");
195 return true;
198 namespace
201 struct lcl_LabeledSequenceEquals
203 explicit lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) :
204 m_bHasLabels ( false ),
205 m_bHasValues ( false )
207 if( !xLSeqToCmp.is())
208 return;
210 Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues());
211 if( xSeq.is())
213 m_bHasValues = true;
214 m_aValuesRangeRep = xSeq->getSourceRangeRepresentation();
217 xSeq.set( xLSeqToCmp->getLabel());
218 if( xSeq.is())
220 m_bHasLabels = true;
221 m_aLabelRangeRep = xSeq->getSourceRangeRepresentation();
225 bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq )
227 if( ! xSeq.is())
228 return false;
230 Reference< data::XDataSequence > xSeqValues( xSeq->getValues() );
231 Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() );
232 bool bHasValues = xSeqValues.is();
233 bool bHasLabels = xSeqLabels.is();
235 return ( ( (m_bHasValues == bHasValues) &&
236 (!bHasValues || m_aValuesRangeRep == xSeqValues->getSourceRangeRepresentation()) ) &&
237 ( (m_bHasLabels == bHasLabels) &&
238 (!bHasLabels || m_aLabelRangeRep == xSeqLabels->getSourceRangeRepresentation()) )
242 private:
243 bool m_bHasLabels;
244 bool m_bHasValues;
245 OUString m_aValuesRangeRep;
246 OUString m_aLabelRangeRep;
249 } // anonymous namespace
251 rtl::Reference< DataSource > DataInterpreter::mergeInterpretedData(
252 const InterpretedData& aInterpretedData )
254 std::vector< Reference< data::XLabeledDataSequence > > aResultVec;
255 aResultVec.reserve( aInterpretedData.Series.size() +
256 1 // categories
259 if( aInterpretedData.Categories.is())
260 aResultVec.push_back( aInterpretedData.Categories );
262 const std::vector< rtl::Reference< DataSeries > > aSeries = FlattenSequence( aInterpretedData.Series );
263 for( rtl::Reference< DataSeries > const & dataSeries : aSeries )
267 // add all sequences of data series
268 for( uno::Reference< data::XLabeledDataSequence > const & xAdd : dataSeries->getDataSequences2() )
270 // only add if sequence is not yet in the result
271 if( none_of( aResultVec.begin(), aResultVec.end(),
272 lcl_LabeledSequenceEquals( xAdd )) )
274 aResultVec.push_back( xAdd );
278 catch( const uno::Exception & )
280 DBG_UNHANDLED_EXCEPTION("chart2");
284 return new DataSource(aResultVec);
287 uno::Any DataInterpreter::getChartTypeSpecificData(
288 const OUString & )
290 return uno::Any();
293 // convenience methods
295 OUString DataInterpreter::GetRole( const Reference< data::XDataSequence > & xSeq )
297 OUString aResult;
298 if( ! xSeq.is())
299 return aResult;
303 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
304 xProp->getPropertyValue( u"Role"_ustr) >>= aResult;
306 catch( const uno::Exception & )
308 DBG_UNHANDLED_EXCEPTION("chart2");
310 return aResult;
313 void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole )
315 if( ! xSeq.is())
316 return;
319 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
320 xProp->setPropertyValue( u"Role"_ustr, uno::Any( rRole ));
322 catch( const uno::Exception & )
324 DBG_UNHANDLED_EXCEPTION("chart2");
328 uno::Any DataInterpreter::GetProperty(
329 const Sequence< beans::PropertyValue > & aArguments,
330 std::u16string_view rName )
332 for( sal_Int32 i=aArguments.getLength(); i--; )
334 if( aArguments[i].Name == rName )
335 return aArguments[i].Value;
337 return uno::Any();
340 bool DataInterpreter::HasCategories(
341 const Sequence< beans::PropertyValue > & rArguments,
342 const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & rData )
344 bool bHasCategories = false;
346 if( rArguments.hasElements() )
347 GetProperty( rArguments, u"HasCategories" ) >>= bHasCategories;
349 for( std::size_t nLSeqIdx=0; ! bHasCategories && nLSeqIdx<rData.size(); ++nLSeqIdx )
350 bHasCategories = ( rData[nLSeqIdx].is() && GetRole( rData[nLSeqIdx]->getValues() ) == "categories");
352 return bHasCategories;
355 bool DataInterpreter::UseCategoriesAsX( const Sequence< beans::PropertyValue > & rArguments )
357 bool bUseCategoriesAsX = true;
358 if( rArguments.hasElements() )
359 GetProperty( rArguments, u"UseCategoriesAsX" ) >>= bUseCategoriesAsX;
360 return bUseCategoriesAsX;
363 OUString SAL_CALL DataInterpreter::getImplementationName()
365 return u"com.sun.star.comp.chart2.DataInterpreter"_ustr;
368 sal_Bool SAL_CALL DataInterpreter::supportsService( const OUString& rServiceName )
370 return cppu::supportsService(this, rServiceName);
373 css::uno::Sequence< OUString > SAL_CALL DataInterpreter::getSupportedServiceNames()
375 return { u"com.sun.star.chart2.DataInterpreter"_ustr };
378 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > DataInterpreter::getDataSequences(
379 const css::uno::Reference< css::chart2::data::XDataSource >& xSource)
381 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData;
382 for (const Reference< data::XLabeledDataSequence > & rLDS : xSource->getDataSequences() )
384 aData.push_back(rLDS);
386 return aData;
389 } // namespace chart
391 #ifdef DEBUG_CHART2_TEMPLATE
392 namespace
395 void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource )
397 if( ! xSource.is())
398 return;
400 SAL_INFO("chart2", "DataSource in DataInterpreter:" );
401 Sequence< Reference< data::XLabeledDataSequence > > aSequences( xSource->getDataSequences());
402 Reference< beans::XPropertySet > xProp;
403 OUString aId;
404 const sal_Int32 nMax = aSequences.getLength();
405 for( sal_Int32 k = 0; k < nMax; ++k )
407 if( aSequences[k].is())
409 OUString aSourceRepr("<none>");
410 if( aSequences[k]->getValues().is())
411 aSourceRepr = aSequences[k]->getValues()->getSourceRangeRepresentation();
412 xProp.set( aSequences[k]->getValues(), uno::UNO_QUERY );
413 if( xProp.is() &&
414 ( xProp->getPropertyValue( "Role") >>= aId ))
416 SAL_INFO("chart2", " <data sequence " << k << "> Role: " << aId << ", Source: "<< aSourceRepr);
418 else
420 SAL_INFO("chart2", " <data sequence " << k << "> unknown Role, Source: " << aSourceRepr );
423 aSourceRepr = "<none>";
424 if( aSequences[k]->getLabel().is())
425 aSourceRepr = aSequences[k]->getLabel()->getSourceRangeRepresentation();
426 xProp.set( aSequences[k]->getLabel(), uno::UNO_QUERY );
427 if( xProp.is() &&
428 ( xProp->getPropertyValue( "Role") >>= aId ))
430 SAL_INFO("chart2", " <data sequence label " << k << "> Role: " << aId
431 << ", Source: " << aSourceRepr );
433 else
435 SAL_INFO("chart2", " <data sequence label " << k << "> unknown Role, Source: " << aSourceRepr );
442 #endif
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */