1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_chart2.hxx" 30 31 #include "DataInterpreter.hxx" 32 #include "DataSeries.hxx" 33 #include "DataSourceHelper.hxx" 34 #include "DataSeriesHelper.hxx" 35 #include "macros.hxx" 36 #include "CommonConverters.hxx" 37 #include "ContainerHelper.hxx" 38 #include <com/sun/star/beans/XPropertySet.hpp> 39 #include <com/sun/star/chart2/data/XDataSink.hpp> 40 41 #include <vector> 42 #include <algorithm> 43 #include <iterator> 44 45 using namespace ::com::sun::star; 46 using namespace ::com::sun::star::chart2; 47 using namespace ::std; 48 using namespace ::chart::ContainerHelper; 49 50 using ::com::sun::star::uno::Reference; 51 using ::com::sun::star::uno::Sequence; 52 using ::rtl::OUString; 53 54 #if OSL_DEBUG_LEVEL > 1 55 namespace 56 { 57 void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource ); 58 } 59 #endif 60 61 namespace chart 62 { 63 64 DataInterpreter::DataInterpreter( 65 const Reference< uno::XComponentContext > & xContext ) : 66 m_xContext( xContext ) 67 {} 68 69 DataInterpreter::~DataInterpreter() 70 {} 71 72 Reference< uno::XComponentContext > DataInterpreter::GetComponentContext() const 73 { 74 return m_xContext; 75 } 76 77 // ____ XDataInterpreter ____ 78 InterpretedData SAL_CALL DataInterpreter::interpretDataSource( 79 const Reference< data::XDataSource >& xSource, 80 const Sequence< beans::PropertyValue >& aArguments, 81 const Sequence< Reference< XDataSeries > >& aSeriesToReUse ) 82 throw (uno::RuntimeException) 83 { 84 if( ! xSource.is()) 85 return InterpretedData(); 86 87 #if OSL_DEBUG_LEVEL > 2 88 lcl_ShowDataSource( xSource ); 89 #endif 90 91 Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() ); 92 93 Reference< data::XLabeledDataSequence > xCategories; 94 vector< Reference< data::XLabeledDataSequence > > aSequencesVec; 95 96 // check if we should use categories 97 98 bool bHasCategories( HasCategories( aArguments, aData )); 99 100 // parse data 101 bool bCategoriesUsed = false; 102 for( sal_Int32 i=0; i < aData.getLength(); ++i ) 103 { 104 try 105 { 106 if( bHasCategories && ! bCategoriesUsed ) 107 { 108 xCategories.set( aData[i] ); 109 if( xCategories.is()) 110 SetRole( xCategories->getValues(), C2U("categories")); 111 bCategoriesUsed = true; 112 } 113 else 114 { 115 aSequencesVec.push_back( aData[i] ); 116 if( aData[i].is()) 117 SetRole( aData[i]->getValues(), C2U("values-y")); 118 } 119 } 120 catch( uno::Exception & ex ) 121 { 122 ASSERT_EXCEPTION( ex ); 123 } 124 } 125 126 // create DataSeries 127 vector< Reference< data::XLabeledDataSequence > >::const_iterator 128 aSequencesVecIt = aSequencesVec.begin(); 129 130 sal_Int32 nSeriesIndex = 0; 131 vector< Reference< XDataSeries > > aSeriesVec; 132 aSeriesVec.reserve( aSequencesVec.size()); 133 134 for( ;aSequencesVecIt != aSequencesVec.end(); ++aSequencesVecIt, ++nSeriesIndex ) 135 { 136 Sequence< Reference< data::XLabeledDataSequence > > aNewData( & (*aSequencesVecIt), 1 ); 137 Reference< XDataSeries > xSeries; 138 if( nSeriesIndex < aSeriesToReUse.getLength()) 139 xSeries.set( aSeriesToReUse[nSeriesIndex] ); 140 else 141 xSeries.set( new DataSeries( GetComponentContext() )); 142 OSL_ASSERT( xSeries.is() ); 143 Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY ); 144 OSL_ASSERT( xSink.is() ); 145 xSink->setData( aNewData ); 146 147 aSeriesVec.push_back( xSeries ); 148 } 149 150 Sequence< Sequence< Reference< XDataSeries > > > aSeries(1); 151 aSeries[0] = ContainerToSequence( aSeriesVec ); 152 return InterpretedData( aSeries, xCategories ); 153 } 154 155 InterpretedData SAL_CALL DataInterpreter::reinterpretDataSeries( 156 const InterpretedData& aInterpretedData ) 157 throw (uno::RuntimeException) 158 { 159 InterpretedData aResult( aInterpretedData ); 160 161 sal_Int32 i=0; 162 Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); 163 const sal_Int32 nCount = aSeries.getLength(); 164 for( ; i<nCount; ++i ) 165 { 166 try 167 { 168 Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW ); 169 Sequence< Reference< data::XLabeledDataSequence > > aNewSequences; 170 171 // values-y 172 Reference< data::XLabeledDataSequence > xValuesY( 173 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false )); 174 // re-use values-... as values-y 175 if( ! xValuesY.is()) 176 { 177 xValuesY.set( 178 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values"), true )); 179 if( xValuesY.is()) 180 SetRole( xValuesY->getValues(), C2U("values-y")); 181 } 182 if( xValuesY.is()) 183 { 184 aNewSequences.realloc(1); 185 aNewSequences[0] = xValuesY; 186 } 187 188 Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences()); 189 if( aSeqs.getLength() != aNewSequences.getLength() ) 190 { 191 #if OSL_DEBUG_LEVEL > 1 192 sal_Int32 j=0; 193 for( ; j<aSeqs.getLength(); ++j ) 194 { 195 OSL_ENSURE( aSeqs[j] == xValuesY, "All sequences should be used" ); 196 } 197 #endif 198 Reference< data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY_THROW ); 199 xSink->setData( aNewSequences ); 200 } 201 } 202 catch( uno::Exception & ex ) 203 { 204 ASSERT_EXCEPTION( ex ); 205 } 206 } 207 208 return aResult; 209 } 210 211 // criterion: all series must have exactly one data::XLabeledDataSequence 212 sal_Bool SAL_CALL DataInterpreter::isDataCompatible( 213 const chart2::InterpretedData& aInterpretedData ) 214 throw (uno::RuntimeException) 215 { 216 Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); 217 for( sal_Int32 i=0; i<aSeries.getLength(); ++i ) 218 { 219 try 220 { 221 Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW ); 222 Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences()); 223 if( aSeq.getLength() != 1 ) 224 return sal_False; 225 } 226 catch( uno::Exception & ex ) 227 { 228 ASSERT_EXCEPTION( ex ); 229 } 230 } 231 232 return sal_True; 233 } 234 235 namespace 236 { 237 238 struct lcl_LabeledSequenceEquals : public unary_function< Reference< data::XLabeledDataSequence >, bool > 239 { 240 lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) : 241 m_bHasLabels ( false ), 242 m_bHasValues ( false ) 243 { 244 if( xLSeqToCmp.is()) 245 { 246 Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues()); 247 if( xSeq.is()) 248 { 249 m_bHasValues = true; 250 m_aValuesRangeRep = xSeq->getSourceRangeRepresentation(); 251 } 252 253 xSeq.set( xLSeqToCmp->getLabel()); 254 if( xSeq.is()) 255 { 256 m_bHasLabels = true; 257 m_aLabelRangeRep = xSeq->getSourceRangeRepresentation(); 258 } 259 } 260 } 261 262 bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq ) 263 { 264 if( ! xSeq.is()) 265 return false; 266 267 Reference< data::XDataSequence > xSeqValues( xSeq->getValues() ); 268 Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() ); 269 bool bHasValues = xSeqValues.is(); 270 bool bHasLabels = xSeqLabels.is(); 271 272 return ( ( (m_bHasValues == bHasValues) && 273 (!bHasValues || m_aValuesRangeRep.equals( xSeqValues->getSourceRangeRepresentation())) ) && 274 ( (m_bHasLabels == bHasLabels) && 275 (!bHasLabels || m_aLabelRangeRep.equals( xSeqLabels->getSourceRangeRepresentation())) ) 276 ); 277 } 278 279 private: 280 bool m_bHasLabels; 281 bool m_bHasValues; 282 OUString m_aValuesRangeRep; 283 OUString m_aLabelRangeRep; 284 }; 285 286 } // anonymous namespace 287 288 Reference< data::XDataSource > SAL_CALL DataInterpreter::mergeInterpretedData( 289 const InterpretedData& aInterpretedData ) 290 throw (uno::RuntimeException) 291 { 292 vector< Reference< data::XLabeledDataSequence > > aResultVec; 293 aResultVec.reserve( aInterpretedData.Series.getLength() + 294 1 // categories 295 ); 296 297 if( aInterpretedData.Categories.is()) 298 aResultVec.push_back( aInterpretedData.Categories ); 299 300 Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); 301 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx ) 302 { 303 try 304 { 305 Reference< data::XDataSource > xSrc( aSeries[nSeriesIdx], uno::UNO_QUERY_THROW ); 306 Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences()); 307 308 // add all sequences of data series 309 for( sal_Int32 nSeqIdx=0; nSeqIdx<aSeq.getLength(); ++nSeqIdx ) 310 { 311 Reference< data::XLabeledDataSequence > xAdd( aSeq[nSeqIdx] ); 312 313 // only add if sequence is not yet in the result 314 if( find_if( aResultVec.begin(), aResultVec.end(), 315 lcl_LabeledSequenceEquals( xAdd )) == aResultVec.end()) 316 { 317 aResultVec.push_back( xAdd ); 318 } 319 } 320 } 321 catch( uno::Exception & ex ) 322 { 323 ASSERT_EXCEPTION( ex ); 324 } 325 } 326 327 return Reference< data::XDataSource >( DataSourceHelper::createDataSource( ContainerToSequence( aResultVec ) ) ); 328 } 329 330 // convenience methods 331 332 OUString DataInterpreter::GetRole( const Reference< data::XDataSequence > & xSeq ) 333 { 334 OUString aResult; 335 if( ! xSeq.is()) 336 return aResult; 337 338 try 339 { 340 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); 341 xProp->getPropertyValue( C2U("Role")) >>= aResult; 342 } 343 catch( uno::Exception & ex ) 344 { 345 ASSERT_EXCEPTION( ex ); 346 } 347 return aResult; 348 } 349 350 void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole ) 351 { 352 if( ! xSeq.is()) 353 return; 354 try 355 { 356 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); 357 xProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole )); 358 } 359 catch( uno::Exception & ex ) 360 { 361 ASSERT_EXCEPTION( ex ); 362 } 363 } 364 365 uno::Any DataInterpreter::GetProperty( 366 const Sequence< beans::PropertyValue > & aArguments, 367 const OUString & rName ) 368 { 369 for( sal_Int32 i=aArguments.getLength(); i--; ) 370 { 371 if( aArguments[i].Name.equals( rName )) 372 return aArguments[i].Value; 373 } 374 return uno::Any(); 375 } 376 377 bool DataInterpreter::HasCategories( 378 const Sequence< beans::PropertyValue > & rArguments, 379 const Sequence< Reference< data::XLabeledDataSequence > > & rData ) 380 { 381 bool bHasCategories = false; 382 383 if( rArguments.getLength() > 0 ) 384 GetProperty( rArguments, C2U(("HasCategories"))) >>= bHasCategories; 385 386 for( sal_Int32 nLSeqIdx=0; ! bHasCategories && nLSeqIdx<rData.getLength(); ++nLSeqIdx ) 387 bHasCategories = ( rData[nLSeqIdx].is() && 388 GetRole( rData[nLSeqIdx]->getValues()).equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("categories"))); 389 390 return bHasCategories; 391 } 392 393 bool DataInterpreter::UseCategoriesAsX( const Sequence< beans::PropertyValue > & rArguments ) 394 { 395 bool bUseCategoriesAsX = true; 396 if( rArguments.getLength() > 0 ) 397 GetProperty( rArguments, C2U(("UseCategoriesAsX"))) >>= bUseCategoriesAsX; 398 return bUseCategoriesAsX; 399 } 400 401 // ------------------------------------------------------------ 402 403 Sequence< OUString > DataInterpreter::getSupportedServiceNames_Static() 404 { 405 Sequence< OUString > aServices( 1 ); 406 aServices[0] = C2U( "com.sun.star.chart2.DataInterpreter" ); 407 return aServices; 408 } 409 410 // implement XServiceInfo methods basing upon getSupportedServiceNames_Static 411 APPHELPER_XSERVICEINFO_IMPL( DataInterpreter, C2U("com.sun.star.comp.chart2.DataInterpreter")); 412 413 } // namespace chart 414 415 #if OSL_DEBUG_LEVEL > 1 416 namespace 417 { 418 419 void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource ) 420 { 421 if( ! xSource.is()) 422 return; 423 424 OSL_TRACE( "DataSource in DataInterpreter:" ); 425 Sequence< Reference< data::XLabeledDataSequence > > aSequences( xSource->getDataSequences()); 426 Reference< beans::XPropertySet > xProp; 427 OUString aId; 428 const sal_Int32 nMax = aSequences.getLength(); 429 for( sal_Int32 k = 0; k < nMax; ++k ) 430 { 431 if( aSequences[k].is()) 432 { 433 OUString aSourceRepr(C2U("<none>")); 434 if( aSequences[k]->getValues().is()) 435 aSourceRepr = aSequences[k]->getValues()->getSourceRangeRepresentation(); 436 xProp.set( aSequences[k]->getValues(), uno::UNO_QUERY ); 437 if( xProp.is() && 438 ( xProp->getPropertyValue( C2U( "Role" )) >>= aId )) 439 { 440 OSL_TRACE( " <data sequence %d> Role: %s, Source: %s", k, U2C( aId ), U2C( aSourceRepr )); 441 } 442 else 443 { 444 OSL_TRACE( " <data sequence %d> unknown Role, Source: %s", k, U2C( aSourceRepr ) ); 445 } 446 447 aSourceRepr = C2U("<none>"); 448 if( aSequences[k]->getLabel().is()) 449 aSourceRepr = OUString( aSequences[k]->getLabel()->getSourceRangeRepresentation()); 450 xProp.set( aSequences[k]->getLabel(), uno::UNO_QUERY ); 451 if( xProp.is() && 452 ( xProp->getPropertyValue( C2U( "Role" )) >>= aId )) 453 { 454 OSL_TRACE( " <data sequence label %d> Role: %s, Source: %s", k, U2C( aId ), U2C( aSourceRepr )); 455 } 456 else 457 { 458 OSL_TRACE( " <data sequence label %d> unknown Role, Source: %s", k, U2C( aSourceRepr ) ); 459 } 460 } 461 } 462 } 463 464 } 465 #endif 466