Bump for 3.6-28
[LibreOffice.git] / chart2 / source / tools / ExplicitCategoriesProvider.cxx
blobc593a51ef9d9cb6657e63ff2367b1db05536a97a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "ExplicitCategoriesProvider.hxx"
31 #include "DiagramHelper.hxx"
32 #include "ChartTypeHelper.hxx"
33 #include "AxisHelper.hxx"
34 #include "CommonConverters.hxx"
35 #include "DataSourceHelper.hxx"
36 #include "ChartModelHelper.hxx"
37 #include "ContainerHelper.hxx"
38 #include "macros.hxx"
39 #include "NumberFormatterWrapper.hxx"
41 #include <com/sun/star/chart2/AxisType.hpp>
42 #include <com/sun/star/util/NumberFormat.hpp>
43 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
45 //.............................................................................
46 namespace chart
48 //.............................................................................
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::chart2;
52 using ::com::sun::star::uno::Reference;
53 using ::com::sun::star::uno::Sequence;
54 using ::rtl::OUString;
55 using ::std::vector;
58 ExplicitCategoriesProvider::ExplicitCategoriesProvider( const Reference< chart2::XCoordinateSystem >& xCooSysModel
59 , const uno::Reference< frame::XModel >& xChartModel )
60 : m_bDirty(true)
61 , m_xCooSysModel( xCooSysModel )
62 , m_xChartModel( xChartModel )
63 , m_xOriginalCategories()
64 , m_bIsExplicitCategoriesInited(false)
65 , m_bIsDateAxis(false)
66 , m_bIsAutoDate(false)
68 try
70 if( xCooSysModel.is() )
72 uno::Reference< XAxis > xAxis( xCooSysModel->getAxisByDimension(0,0) );
73 if( xAxis.is() )
75 ScaleData aScale( xAxis->getScaleData() );
76 m_xOriginalCategories = aScale.Categories;
77 m_bIsAutoDate = (aScale.AutoDateAxis && aScale.AxisType==chart2::AxisType::CATEGORY);
78 m_bIsDateAxis = (aScale.AxisType == chart2::AxisType::DATE || m_bIsAutoDate);
82 if( m_xOriginalCategories.is() )
84 Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY );
85 if( xChartDoc.is() )
87 uno::Reference< data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
89 OUString aCategoriesRange( DataSourceHelper::getRangeFromValues( m_xOriginalCategories ) );
90 if( xDataProvider.is() && !aCategoriesRange.isEmpty() )
92 const bool bFirstCellAsLabel = false;
93 const bool bHasCategories = false;
94 const uno::Sequence< sal_Int32 > aSequenceMapping;
96 uno::Reference< data::XDataSource > xColumnCategoriesSource( xDataProvider->createDataSource(
97 DataSourceHelper::createArguments( aCategoriesRange, aSequenceMapping, true /*bUseColumns*/
98 , bFirstCellAsLabel, bHasCategories ) ) );
100 uno::Reference< data::XDataSource > xRowCategoriesSource( xDataProvider->createDataSource(
101 DataSourceHelper::createArguments( aCategoriesRange, aSequenceMapping, false /*bUseColumns*/
102 , bFirstCellAsLabel, bHasCategories ) ) );
104 if( xColumnCategoriesSource.is() && xRowCategoriesSource.is() )
106 Sequence< Reference< data::XLabeledDataSequence> > aColumns = xColumnCategoriesSource->getDataSequences();
107 Sequence< Reference< data::XLabeledDataSequence> > aRows = xRowCategoriesSource->getDataSequences();
109 sal_Int32 nColumnCount = aColumns.getLength();
110 sal_Int32 nRowCount = aRows.getLength();
111 if( nColumnCount>1 && nRowCount>1 )
113 //we have complex categories
114 //->split them in the direction of the first series
115 //detect whether the first series is a row or a column
116 bool bSeriesUsesColumns = true;
117 ::std::vector< Reference< XDataSeries > > aSeries( ChartModelHelper::getDataSeries( xChartModel ) );
118 if( !aSeries.empty() )
120 uno::Reference< data::XDataSource > xSeriesSource( aSeries.front(), uno::UNO_QUERY );
121 ::rtl::OUString aStringDummy;
122 bool bDummy;
123 uno::Sequence< sal_Int32 > aSeqDummy;
124 DataSourceHelper::readArguments( xDataProvider->detectArguments( xSeriesSource),
125 aStringDummy, aSeqDummy, bSeriesUsesColumns, bDummy, bDummy );
127 if( bSeriesUsesColumns )
128 m_aSplitCategoriesList=aColumns;
129 else
130 m_aSplitCategoriesList=aRows;
135 if( !m_aSplitCategoriesList.getLength() )
137 m_aSplitCategoriesList.realloc(1);
138 m_aSplitCategoriesList[0]=m_xOriginalCategories;
142 catch( const uno::Exception & ex )
144 ASSERT_EXCEPTION( ex );
148 ExplicitCategoriesProvider::~ExplicitCategoriesProvider()
152 Reference< chart2::data::XDataSequence > ExplicitCategoriesProvider::getOriginalCategories()
154 if( m_xOriginalCategories.is() )
155 return m_xOriginalCategories->getValues();
156 return 0;
159 const Sequence< Reference< data::XLabeledDataSequence> >& ExplicitCategoriesProvider::getSplitCategoriesList()
161 return m_aSplitCategoriesList;
164 bool ExplicitCategoriesProvider::hasComplexCategories() const
166 return m_aSplitCategoriesList.getLength() > 1;
169 sal_Int32 ExplicitCategoriesProvider::getCategoryLevelCount() const
171 sal_Int32 nCount = m_aSplitCategoriesList.getLength();
172 if(!nCount)
173 nCount = 1;
174 return nCount;
177 std::vector<sal_Int32> lcl_getLimitingBorders( const std::vector< ComplexCategory >& rComplexCategories )
179 std::vector<sal_Int32> aLimitingBorders;
180 std::vector< ComplexCategory >::const_iterator aIt( rComplexCategories.begin() );
181 std::vector< ComplexCategory >::const_iterator aEnd( rComplexCategories.end() );
182 sal_Int32 nBorderIndex = 0; /*border below the index*/
183 for( ; aIt != aEnd; ++aIt )
185 ComplexCategory aComplexCategory(*aIt);
186 nBorderIndex += aComplexCategory.Count;
187 aLimitingBorders.push_back(nBorderIndex);
189 return aLimitingBorders;
192 void ExplicitCategoriesProvider::convertCategoryAnysToText( uno::Sequence< rtl::OUString >& rOutTexts, const uno::Sequence< uno::Any >& rInAnys, Reference< frame::XModel > xChartModel )
194 sal_Int32 nCount = rInAnys.getLength();
195 if(!nCount)
196 return;
197 rOutTexts.realloc(nCount);
198 Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartModel, uno::UNO_QUERY );
199 Reference< util::XNumberFormats > xNumberFormats;
200 if( xNumberFormatsSupplier.is() )
201 xNumberFormats = Reference< util::XNumberFormats >( xNumberFormatsSupplier->getNumberFormats() );
203 sal_Int32 nAxisNumberFormat = 0;
204 Reference< XCoordinateSystem > xCooSysModel( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
205 if( xCooSysModel.is() )
207 Reference< chart2::XAxis > xAxis( xCooSysModel->getAxisByDimension(0,0) );
208 nAxisNumberFormat = AxisHelper::getExplicitNumberFormatKeyForAxis(
209 xAxis, xCooSysModel, xNumberFormatsSupplier, false );
212 sal_Int32 nLabelColor;
213 bool bColorChanged = false;
215 NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
217 for(sal_Int32 nN=0;nN<nCount;nN++)
219 rtl::OUString aText;
220 uno::Any aAny = rInAnys[nN];
221 if( aAny.hasValue() )
223 double fDouble = 0;
224 if( aAny>>=fDouble )
226 if( !::rtl::math::isNan(fDouble) )
227 aText = aNumberFormatterWrapper.getFormattedString(
228 nAxisNumberFormat, fDouble, nLabelColor, bColorChanged );
230 else
232 aAny>>=aText;
235 rOutTexts[nN] = aText;
239 SplitCategoriesProvider::~SplitCategoriesProvider()
243 class SplitCategoriesProvider_ForLabeledDataSequences : public SplitCategoriesProvider
245 public:
247 explicit SplitCategoriesProvider_ForLabeledDataSequences(
248 const ::com::sun::star::uno::Sequence<
249 ::com::sun::star::uno::Reference<
250 ::com::sun::star::chart2::data::XLabeledDataSequence> >& rSplitCategoriesList
251 , const Reference< frame::XModel >& xChartModel )
252 : m_rSplitCategoriesList( rSplitCategoriesList )
253 , m_xChartModel( xChartModel )
255 virtual ~SplitCategoriesProvider_ForLabeledDataSequences()
258 virtual sal_Int32 getLevelCount() const;
259 virtual uno::Sequence< rtl::OUString > getStringsForLevel( sal_Int32 nIndex ) const;
261 private:
262 const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference<
263 ::com::sun::star::chart2::data::XLabeledDataSequence> >& m_rSplitCategoriesList;
265 Reference< frame::XModel > m_xChartModel;
268 sal_Int32 SplitCategoriesProvider_ForLabeledDataSequences::getLevelCount() const
270 return m_rSplitCategoriesList.getLength();
272 uno::Sequence< rtl::OUString > SplitCategoriesProvider_ForLabeledDataSequences::getStringsForLevel( sal_Int32 nLevel ) const
274 uno::Sequence< rtl::OUString > aRet;
275 Reference< data::XLabeledDataSequence > xLabeledDataSequence( m_rSplitCategoriesList[nLevel] );
276 if( xLabeledDataSequence.is() )
278 uno::Reference< data::XDataSequence > xDataSequence( xLabeledDataSequence->getValues() );
279 if( xDataSequence.is() )
280 ExplicitCategoriesProvider::convertCategoryAnysToText( aRet, xDataSequence->getData(), m_xChartModel );
282 return aRet;
285 std::vector< ComplexCategory > lcl_DataSequenceToComplexCategoryVector(
286 const uno::Sequence< rtl::OUString >& rStrings
287 , const std::vector<sal_Int32>& rLimitingBorders, bool bCreateSingleCategories )
289 std::vector< ComplexCategory > aResult;
291 sal_Int32 nMaxCount = rStrings.getLength();
292 OUString aPrevious;
293 sal_Int32 nCurrentCount=0;
294 for( sal_Int32 nN=0; nN<nMaxCount; nN++ )
296 const OUString& aCurrent = rStrings[nN];
297 if( bCreateSingleCategories || ::std::find( rLimitingBorders.begin(), rLimitingBorders.end(), nN ) != rLimitingBorders.end() )
299 aResult.push_back( ComplexCategory(aPrevious,nCurrentCount) );
300 nCurrentCount=1;
301 aPrevious = aCurrent;
303 else
305 // Empty value is interpreted as a continuation of the previous
306 // category. Note that having the same value as the previous one
307 // does not equate to a continuation of the category.
309 if (aCurrent.isEmpty())
310 ++nCurrentCount;
311 else
313 aResult.push_back( ComplexCategory(aPrevious,nCurrentCount) );
314 nCurrentCount=1;
315 aPrevious = aCurrent;
319 if( nCurrentCount )
320 aResult.push_back( ComplexCategory(aPrevious,nCurrentCount) );
322 return aResult;
325 sal_Int32 lcl_getCategoryCount( std::vector< ComplexCategory >& rComplexCategories )
327 sal_Int32 nCount = 0;
328 std::vector< ComplexCategory >::const_iterator aIt( rComplexCategories.begin() );
329 std::vector< ComplexCategory >::const_iterator aEnd( rComplexCategories.end() );
330 for( ; aIt != aEnd; ++aIt )
331 nCount+=aIt->Count;
332 return nCount;
335 Sequence< OUString > lcl_getExplicitSimpleCategories(
336 const SplitCategoriesProvider& rSplitCategoriesProvider,
337 ::std::vector< ::std::vector< ComplexCategory > >& rComplexCats )
339 Sequence< OUString > aRet;
341 rComplexCats.clear();
342 sal_Int32 nLCount = rSplitCategoriesProvider.getLevelCount();
343 for( sal_Int32 nL = 0; nL < nLCount; nL++ )
345 std::vector<sal_Int32> aLimitingBorders;
346 if(nL>0)
347 aLimitingBorders = lcl_getLimitingBorders( rComplexCats.back() );
348 rComplexCats.push_back( lcl_DataSequenceToComplexCategoryVector(
349 rSplitCategoriesProvider.getStringsForLevel(nL), aLimitingBorders, nL==(nLCount-1) ) );
352 std::vector< std::vector< ComplexCategory > >::iterator aOuterIt( rComplexCats.begin() );
353 std::vector< std::vector< ComplexCategory > >::const_iterator aOuterEnd( rComplexCats.end() );
355 //ensure that the category count is the same on each level
356 sal_Int32 nMaxCategoryCount = 0;
358 for( aOuterIt=rComplexCats.begin(); aOuterIt != aOuterEnd; ++aOuterIt )
360 sal_Int32 nCurrentCount = lcl_getCategoryCount( *aOuterIt );
361 nMaxCategoryCount = std::max( nCurrentCount, nMaxCategoryCount );
363 for( aOuterIt=rComplexCats.begin(); aOuterIt != aOuterEnd; ++aOuterIt )
365 if ( !aOuterIt->empty() )
367 sal_Int32 nCurrentCount = lcl_getCategoryCount( *aOuterIt );
368 if( nCurrentCount< nMaxCategoryCount )
370 ComplexCategory& rComplexCategory = aOuterIt->back();
371 rComplexCategory.Count += (nMaxCategoryCount-nCurrentCount);
377 //create a list with an element for every index
378 std::vector< std::vector< ComplexCategory > > aComplexCatsPerIndex;
379 for( aOuterIt=rComplexCats.begin() ; aOuterIt != aOuterEnd; ++aOuterIt )
381 std::vector< ComplexCategory > aSingleLevel;
382 std::vector< ComplexCategory >::iterator aIt( aOuterIt->begin() );
383 std::vector< ComplexCategory >::const_iterator aEnd( aOuterIt->end() );
384 for( ; aIt != aEnd; ++aIt )
386 ComplexCategory aComplexCategory( *aIt );
387 sal_Int32 nCount = aComplexCategory.Count;
388 while( nCount-- )
389 aSingleLevel.push_back(aComplexCategory);
391 aComplexCatsPerIndex.push_back( aSingleLevel );
394 if(nMaxCategoryCount)
396 aRet.realloc(nMaxCategoryCount);
397 aOuterEnd = aComplexCatsPerIndex.end();
398 OUString aSpace(C2U(" "));
399 for(sal_Int32 nN=0; nN<nMaxCategoryCount; nN++)
401 OUString aText;
402 for( aOuterIt=aComplexCatsPerIndex.begin() ; aOuterIt != aOuterEnd; ++aOuterIt )
404 if ( static_cast<size_t>(nN) < aOuterIt->size() )
406 OUString aAddText = (*aOuterIt)[nN].Text;
407 if( !aAddText.isEmpty() )
409 if(!aText.isEmpty())
410 aText += aSpace;
411 aText += aAddText;
415 aRet[nN]=aText;
418 return aRet;
421 Sequence< OUString > ExplicitCategoriesProvider::getExplicitSimpleCategories(
422 const SplitCategoriesProvider& rSplitCategoriesProvider )
424 vector< vector< ComplexCategory > > aComplexCats;
425 return lcl_getExplicitSimpleCategories( rSplitCategoriesProvider, aComplexCats );
428 struct DatePlusIndexComparator
430 inline bool operator() ( const DatePlusIndex& aFirst,
431 const DatePlusIndex& aSecond ) const
433 return ( aFirst.fValue < aSecond.fValue );
437 bool lcl_fillDateCategories( const uno::Reference< data::XDataSequence >& xDataSequence, std::vector< DatePlusIndex >& rDateCategories, bool bIsAutoDate, Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier )
439 bool bOnlyDatesFound = true;
440 bool bAnyDataFound = false;
442 if( xDataSequence.is() )
444 uno::Sequence< uno::Any > aValues = xDataSequence->getData();
445 sal_Int32 nCount = aValues.getLength();
446 rDateCategories.reserve(nCount);
447 Reference< util::XNumberFormats > xNumberFormats;
448 if( xNumberFormatsSupplier.is() )
449 xNumberFormats = Reference< util::XNumberFormats >( xNumberFormatsSupplier->getNumberFormats() );
451 bool bOwnData = false;
452 bool bOwnDataAnddAxisHasAnyFormat = false;
453 bool bOwnDataAnddAxisHasDateFormat = false;
454 Reference< chart2::XChartDocument > xChartDoc( xNumberFormatsSupplier, uno::UNO_QUERY );
455 Reference< XCoordinateSystem > xCooSysModel( ChartModelHelper::getFirstCoordinateSystem( Reference< frame::XModel >( xChartDoc, uno::UNO_QUERY ) ) );
456 if( xChartDoc.is() && xCooSysModel.is() )
458 if( xChartDoc->hasInternalDataProvider() )
460 bOwnData = true;
461 Reference< beans::XPropertySet > xAxisProps( xCooSysModel->getAxisByDimension(0,0), uno::UNO_QUERY );
462 sal_Int32 nAxisNumberFormat = 0;
463 if( xAxisProps.is() && (xAxisProps->getPropertyValue( C2U("NumberFormat") ) >>= nAxisNumberFormat) )
465 bOwnDataAnddAxisHasAnyFormat = true;
466 bOwnDataAnddAxisHasDateFormat = DiagramHelper::isDateNumberFormat( nAxisNumberFormat, xNumberFormats );
471 for(sal_Int32 nN=0;nN<nCount;nN++)
473 bool bIsDate = false;
474 if( bIsAutoDate )
476 if( bOwnData )
477 bIsDate = bOwnDataAnddAxisHasAnyFormat ? bOwnDataAnddAxisHasDateFormat : true;
478 else
479 bIsDate = DiagramHelper::isDateNumberFormat( xDataSequence->getNumberFormatKeyByIndex( nN ), xNumberFormats );
481 else
482 bIsDate = true;
484 bool bContainsEmptyString = false;
485 bool bContainsNan = false;
486 uno::Any aAny = aValues[nN];
487 if( aAny.hasValue() )
489 OUString aTest;
490 double fTest = 0;
491 if( (aAny>>=aTest) && aTest.isEmpty() ) //empty String
492 bContainsEmptyString = true;
493 else if( (aAny>>=fTest) && ::rtl::math::isNan(fTest) )
494 bContainsNan = true;
496 if( !bContainsEmptyString && !bContainsNan )
497 bAnyDataFound = true;
499 DatePlusIndex aDatePlusIndex( 1.0, nN );
500 if( bIsDate && (aAny >>= aDatePlusIndex.fValue) )
501 rDateCategories.push_back( aDatePlusIndex );
502 else
504 if( aAny.hasValue() && !bContainsEmptyString )//empty string does not count as non date value!
505 bOnlyDatesFound=false;
506 ::rtl::math::setNan( &aDatePlusIndex.fValue );
507 rDateCategories.push_back( aDatePlusIndex );
510 ::std::sort( rDateCategories.begin(), rDateCategories.end(), DatePlusIndexComparator() );
513 return bAnyDataFound && bOnlyDatesFound;
516 void ExplicitCategoriesProvider::init()
518 if( m_bDirty )
520 m_aComplexCats.clear();//not one per index
521 m_aDateCategories.clear();
523 if( m_xOriginalCategories.is() )
525 if( !hasComplexCategories() )
527 if(m_bIsDateAxis)
529 if( ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( m_xCooSysModel, 0 ), 2, 0 ) )
530 m_bIsDateAxis = lcl_fillDateCategories( m_xOriginalCategories->getValues(), m_aDateCategories, m_bIsAutoDate, Reference< util::XNumberFormatsSupplier >( m_xChartModel.get(), uno::UNO_QUERY ) );
531 else
532 m_bIsDateAxis = false;
535 else
537 m_bIsDateAxis = false;
540 else
541 m_bIsDateAxis=false;
542 m_bDirty = false;
547 Sequence< ::rtl::OUString > ExplicitCategoriesProvider::getSimpleCategories()
549 if( !m_bIsExplicitCategoriesInited )
551 init();
552 m_aExplicitCategories.realloc(0);
553 if( m_xOriginalCategories.is() )
555 if( !hasComplexCategories() )
557 uno::Reference< data::XDataSequence > xDataSequence( m_xOriginalCategories->getValues() );
558 if( xDataSequence.is() )
559 ExplicitCategoriesProvider::convertCategoryAnysToText( m_aExplicitCategories, xDataSequence->getData(), m_xChartModel );
561 else
563 m_aExplicitCategories = lcl_getExplicitSimpleCategories(
564 SplitCategoriesProvider_ForLabeledDataSequences( m_aSplitCategoriesList, m_xChartModel ), m_aComplexCats );
567 if(!m_aExplicitCategories.getLength())
568 m_aExplicitCategories = DiagramHelper::generateAutomaticCategoriesFromCooSys( m_xCooSysModel );
569 m_bIsExplicitCategoriesInited = true;
571 return m_aExplicitCategories;
574 std::vector< ComplexCategory > ExplicitCategoriesProvider::getCategoriesByLevel( sal_Int32 nLevel )
576 std::vector< ComplexCategory > aRet;
577 init();
578 sal_Int32 nMaxIndex = m_aComplexCats.size()-1;
579 if( nLevel >= 0 && nLevel <= nMaxIndex )
580 aRet = m_aComplexCats[nMaxIndex-nLevel];
581 return aRet;
584 OUString ExplicitCategoriesProvider::getCategoryByIndex(
585 const Reference< XCoordinateSystem >& xCooSysModel
586 , const uno::Reference< frame::XModel >& xChartModel
587 , sal_Int32 nIndex )
589 if( xCooSysModel.is())
591 ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSysModel, xChartModel );
592 Sequence< OUString > aCategories( aExplicitCategoriesProvider.getSimpleCategories());
593 if( nIndex < aCategories.getLength())
594 return aCategories[ nIndex ];
596 return OUString();
599 bool ExplicitCategoriesProvider::isDateAxis()
601 init();
602 return m_bIsDateAxis;
605 const std::vector< DatePlusIndex >& ExplicitCategoriesProvider::getDateCategories()
607 init();
608 return m_aDateCategories;
611 //.............................................................................
612 } //namespace chart
613 //.............................................................................
615 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */