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