LibreOffice Module chart2 (master) 1
DataInterpreter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
28
29#include <algorithm>
30#include <cstddef>
31
32using namespace ::com::sun::star;
33using namespace ::com::sun::star::chart2;
34
35using ::com::sun::star::uno::Reference;
36using ::com::sun::star::uno::Sequence;
37
38#ifdef DEBUG_CHART2_TEMPLATE
39namespace
40{
41void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource );
42}
43#endif
44
45namespace chart
46{
47
49{}
50
52{}
53
54// ____ XDataInterpreter ____
56 const Reference< data::XDataSource >& xSource,
57 const Sequence< beans::PropertyValue >& aArguments,
58 const std::vector< rtl::Reference< DataSeries > >& aSeriesToReUse )
59{
60 if( ! xSource.is())
61 return InterpretedData();
62
63#ifdef DEBUG_CHART2_TEMPLATE
64 lcl_ShowDataSource( xSource );
65#endif
66
67 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = getDataSequences(xSource);
68
70 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequencesVec;
71
72 // check if we should use categories
73
74 bool bHasCategories( HasCategories( aArguments, aData ));
75
76 // parse data
77 bool bCategoriesUsed = false;
79 {
80 try
81 {
82 if( bHasCategories && ! bCategoriesUsed )
83 {
84 xCategories = labeledData;
85 if( xCategories.is())
86 SetRole( xCategories->getValues(), "categories");
87 bCategoriesUsed = true;
88 }
89 else
90 {
91 aSequencesVec.push_back( labeledData );
92 if( labeledData.is())
93 SetRole( labeledData->getValues(), "values-y");
94 }
95 }
96 catch( const uno::Exception & )
97 {
99 }
100 }
101
102 // create DataSeries
103 std::size_t nSeriesIndex = 0;
104 std::vector< rtl::Reference< DataSeries > > aSeriesVec;
105 aSeriesVec.reserve( aSequencesVec.size());
106
107 for (auto const& elem : aSequencesVec)
108 {
109 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewData { elem };
111 if( nSeriesIndex < aSeriesToReUse.size())
112 xSeries = aSeriesToReUse[nSeriesIndex];
113 else
114 xSeries = new DataSeries;
115 assert( xSeries.is() );
116 xSeries->setData( aNewData );
117
118 aSeriesVec.push_back( xSeries );
119 ++nSeriesIndex;
120 }
121
122 return { { aSeriesVec }, xCategories };
123}
124
126 const InterpretedData& aInterpretedData )
127{
128 InterpretedData aResult( aInterpretedData );
129
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 )
134 {
135 try
136 {
137 std::vector< uno::Reference< data::XLabeledDataSequence > > aNewSequences;
138
139 // values-y
141 DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-y" );
142 // re-use values-... as values-y
143 if( ! xValuesY.is())
144 {
145 xValuesY =
146 DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values", true );
147 if( xValuesY.is())
148 SetRole( xValuesY->getValues(), "values-y");
149 }
150 if( xValuesY.is())
151 {
152 aNewSequences = { xValuesY };
153 }
154
155 const std::vector< uno::Reference< data::XLabeledDataSequence > > & aSeqs = aSeries[i]->getDataSequences2();
156 if( aSeqs.size() != aNewSequences.size() )
157 {
158#ifdef DEBUG_CHART2_TEMPLATE
159 sal_Int32 j=0;
160 for( ; j<aSeqs.(); ++j )
161 {
162 assert( aSeqs[j] == xValuesY && "All sequences should be used" );
163 }
164#endif
165 aSeries[i]->setData( aNewSequences );
166 }
167 }
168 catch( const uno::Exception & )
169 {
170 DBG_UNHANDLED_EXCEPTION("chart2");
171 }
172 }
173
174 return aResult;
175}
176
177// criterion: all series must have exactly one data::XLabeledDataSequence
179 const InterpretedData& aInterpretedData )
180{
181 const std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
182 for( rtl::Reference< DataSeries > const & i : aSeries )
183 {
184 try
185 {
186 if( i->getDataSequences2().size() != 1 )
187 return false;
188 }
189 catch( const uno::Exception & )
190 {
191 DBG_UNHANDLED_EXCEPTION("chart2");
192 }
193 }
194
195 return true;
196}
197
198namespace
199{
200
201struct lcl_LabeledSequenceEquals
202{
203 explicit lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) :
204 m_bHasLabels ( false ),
205 m_bHasValues ( false )
206 {
207 if( !xLSeqToCmp.is())
208 return;
209
210 Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues());
211 if( xSeq.is())
212 {
213 m_bHasValues = true;
214 m_aValuesRangeRep = xSeq->getSourceRangeRepresentation();
215 }
216
217 xSeq.set( xLSeqToCmp->getLabel());
218 if( xSeq.is())
219 {
220 m_bHasLabels = true;
221 m_aLabelRangeRep = xSeq->getSourceRangeRepresentation();
222 }
223 }
224
225 bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq )
226 {
227 if( ! xSeq.is())
228 return false;
229
230 Reference< data::XDataSequence > xSeqValues( xSeq->getValues() );
231 Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() );
232 bool bHasValues = xSeqValues.is();
233 bool bHasLabels = xSeqLabels.is();
234
235 return ( ( (m_bHasValues == bHasValues) &&
236 (!bHasValues || m_aValuesRangeRep == xSeqValues->getSourceRangeRepresentation()) ) &&
237 ( (m_bHasLabels == bHasLabels) &&
238 (!bHasLabels || m_aLabelRangeRep == xSeqLabels->getSourceRangeRepresentation()) )
239 );
240 }
241
242private:
247};
248
249} // anonymous namespace
250
252 const InterpretedData& aInterpretedData )
253{
254 std::vector< Reference< data::XLabeledDataSequence > > aResultVec;
255 aResultVec.reserve( aInterpretedData.Series.size() +
256 1 // categories
257 );
258
259 if( aInterpretedData.Categories.is())
260 aResultVec.push_back( aInterpretedData.Categories );
261
262 const std::vector< rtl::Reference< DataSeries > > aSeries = FlattenSequence( aInterpretedData.Series );
263 for( rtl::Reference< DataSeries > const & dataSeries : aSeries )
264 {
265 try
266 {
267 // add all sequences of data series
268 for( uno::Reference< data::XLabeledDataSequence > const & xAdd : dataSeries->getDataSequences2() )
269 {
270 // only add if sequence is not yet in the result
271 if( none_of( aResultVec.begin(), aResultVec.end(),
272 lcl_LabeledSequenceEquals( xAdd )) )
273 {
274 aResultVec.push_back( xAdd );
275 }
276 }
277 }
278 catch( const uno::Exception & )
279 {
280 DBG_UNHANDLED_EXCEPTION("chart2");
281 }
282 }
283
284 return new DataSource(aResultVec);
285}
286
288 const OUString & )
289{
290 return uno::Any();
291}
292
293// convenience methods
294
296{
297 OUString aResult;
298 if( ! xSeq.is())
299 return aResult;
300
301 try
302 {
303 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
304 xProp->getPropertyValue( "Role") >>= aResult;
305 }
306 catch( const uno::Exception & )
307 {
308 DBG_UNHANDLED_EXCEPTION("chart2");
309 }
310 return aResult;
311}
312
313void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole )
314{
315 if( ! xSeq.is())
316 return;
317 try
318 {
319 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
320 xProp->setPropertyValue( "Role", uno::Any( rRole ));
321 }
322 catch( const uno::Exception & )
323 {
324 DBG_UNHANDLED_EXCEPTION("chart2");
325 }
326}
327
329 const Sequence< beans::PropertyValue > & aArguments,
330 std::u16string_view rName )
331{
332 for( sal_Int32 i=aArguments.getLength(); i--; )
333 {
334 if( aArguments[i].Name == rName )
335 return aArguments[i].Value;
336 }
337 return uno::Any();
338}
339
341 const Sequence< beans::PropertyValue > & rArguments,
342 const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & rData )
343{
344 bool bHasCategories = false;
345
346 if( rArguments.hasElements() )
347 GetProperty( rArguments, u"HasCategories" ) >>= bHasCategories;
348
349 for( std::size_t nLSeqIdx=0; ! bHasCategories && nLSeqIdx<rData.size(); ++nLSeqIdx )
350 bHasCategories = ( rData[nLSeqIdx].is() && GetRole( rData[nLSeqIdx]->getValues() ) == "categories");
351
352 return bHasCategories;
353}
354
356{
357 bool bUseCategoriesAsX = true;
358 if( rArguments.hasElements() )
359 GetProperty( rArguments, u"UseCategoriesAsX" ) >>= bUseCategoriesAsX;
360 return bUseCategoriesAsX;
361}
362
364{
365 return "com.sun.star.comp.chart2.DataInterpreter";
366}
367
368sal_Bool SAL_CALL DataInterpreter::supportsService( const OUString& rServiceName )
369{
370 return cppu::supportsService(this, rServiceName);
371}
372
373css::uno::Sequence< OUString > SAL_CALL DataInterpreter::getSupportedServiceNames()
374{
375 return { "com.sun.star.chart2.DataInterpreter" };
376}
377
378std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > DataInterpreter::getDataSequences(
379 const css::uno::Reference< css::chart2::data::XDataSource >& xSource)
380{
381 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData;
382 for (const Reference< data::XLabeledDataSequence > & rLDS : xSource->getDataSequences() )
383 {
384 aData.push_back(rLDS);
385 }
386 return aData;
387}
388
389} // namespace chart
390
391#ifdef DEBUG_CHART2_TEMPLATE
392namespace
393{
394
395void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource )
396{
397 if( ! xSource.is())
398 return;
399
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 )
406 {
407 if( aSequences[k].is())
408 {
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 ))
415 {
416 SAL_INFO("chart2", " <data sequence " << k << "> Role: " << aId << ", Source: "<< aSourceRepr);
417 }
418 else
419 {
420 SAL_INFO("chart2", " <data sequence " << k << "> unknown Role, Source: " << aSourceRepr );
421 }
422
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 ))
429 {
430 SAL_INFO("chart2", " <data sequence label " << k << "> Role: " << aId
431 << ", Source: " << aSourceRepr );
432 }
433 else
434 {
435 SAL_INFO("chart2", " <data sequence label " << k << "> unknown Role, Source: " << aSourceRepr );
436 }
437 }
438 }
439}
440
441}
442#endif
443
444/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool m_bHasValues
OUString m_aLabelRangeRep
OUString m_aValuesRangeRep
bool m_bHasLabels
static bool HasCategories(const css::uno::Sequence< css::beans::PropertyValue > &rArguments, const std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > &rData)
static OUString GetRole(const css::uno::Reference< css::chart2::data::XDataSequence > &xSeq)
virtual css::uno::Any getChartTypeSpecificData(const OUString &sKey)
Get chart information that is specific to a particular chart type, by key.
static rtl::Reference< ::chart::DataSource > mergeInterpretedData(const InterpretedData &aInterpretedData)
Try to reverse the operation done in interpretDataSource().
virtual ~DataInterpreter() override
virtual OUString SAL_CALL getImplementationName() override
XServiceInfo declarations.
virtual InterpretedData reinterpretDataSeries(const InterpretedData &aInterpretedData)
Re-interprets the data given in aInterpretedData while keeping the number of data series and the cate...
static std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > getDataSequences(const css::uno::Reference< css::chart2::data::XDataSource > &xSource)
static void SetRole(const css::uno::Reference< css::chart2::data::XDataSequence > &xSeq, const OUString &rRole)
static css::uno::Any GetProperty(const css::uno::Sequence< css::beans::PropertyValue > &aArguments, std::u16string_view rName)
virtual bool isDataCompatible(const InterpretedData &aInterpretedData)
parses the given data and states, if a reinterpretDataSeries() call can be done without data loss.
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
static bool UseCategoriesAsX(const css::uno::Sequence< css::beans::PropertyValue > &rArguments)
virtual InterpretedData interpretDataSource(const css::uno::Reference< css::chart2::data::XDataSource > &xSource, const css::uno::Sequence< css::beans::PropertyValue > &aArguments, const std::vector< rtl::Reference< ::chart::DataSeries > > &aSeriesToReUse)
Interprets the given data.
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
float u
Sequence< PropertyValue > aArguments
#define SAL_INFO(area, stream)
constexpr OUStringLiteral aData
OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XLabeledDataSequence > getDataSequenceByRole(const css::uno::Reference< css::chart2::data::XDataSource > &xSource, const OUString &aRole, bool bMatchPrefix=false)
Retrieves the data sequence in the given data source that matches the given role.
std::vector< T > FlattenSequence(const std::vector< std::vector< T > > &aSeqSeq)
std::vector< std::vector< T > > -> std::vector< T >
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
offers tooling to interpret different data sources in a structural and chart-type-dependent way.
std::vector< std::vector< rtl::Reference<::chart::DataSeries > > > Series
css::uno::Reference< css::chart2::data::XLabeledDataSequence > Categories
OUString Name
unsigned char sal_Bool