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_chartmodel.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 { 79 if( ! xSource.is()) 80 return InterpretedData(); 81 82 #if OSL_DEBUG_LEVEL > 2 83 lcl_ShowDataSource( xSource ); 84 #endif 85 86 Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() ); 87 88 Reference< data::XLabeledDataSequence > xCategories; 89 vector< Reference< data::XLabeledDataSequence > > aSequencesVec; 90 91 // check if we should use categories 92 93 bool bHasCategories( HasCategories( aArguments, aData )); 94 95 // parse data 96 bool bCategoriesUsed = false; 97 for( sal_Int32 i=0; i < aData.getLength(); ++i ) 98 { 99 try 100 { 101 if( bHasCategories && ! bCategoriesUsed ) 102 { 103 xCategories.set( aData[i] ); 104 if( xCategories.is()) 105 SetRole( xCategories->getValues(), C2U("categories")); 106 bCategoriesUsed = true; 107 } 108 else 109 { 110 aSequencesVec.push_back( aData[i] ); 111 if( aData[i].is()) 112 SetRole( aData[i]->getValues(), C2U("values-y")); 113 } 114 } 115 catch( uno::Exception & ex ) 116 { 117 ASSERT_EXCEPTION( ex ); 118 } 119 } 120 121 // create DataSeries 122 vector< Reference< data::XLabeledDataSequence > >::const_iterator 123 aSequencesVecIt = aSequencesVec.begin(); 124 125 sal_Int32 nSeriesIndex = 0; 126 vector< Reference< XDataSeries > > aSeriesVec; 127 aSeriesVec.reserve( aSequencesVec.size()); 128 129 for( ;aSequencesVecIt != aSequencesVec.end(); ++aSequencesVecIt, ++nSeriesIndex ) 130 { 131 Sequence< Reference< data::XLabeledDataSequence > > aNewData( & (*aSequencesVecIt), 1 ); 132 Reference< XDataSeries > xSeries; 133 if( nSeriesIndex < aSeriesToReUse.getLength()) 134 xSeries.set( aSeriesToReUse[nSeriesIndex] ); 135 else 136 xSeries.set( new DataSeries( GetComponentContext() )); 137 OSL_ASSERT( xSeries.is() ); 138 Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY ); 139 OSL_ASSERT( xSink.is() ); 140 xSink->setData( aNewData ); 141 142 aSeriesVec.push_back( xSeries ); 143 } 144 145 Sequence< Sequence< Reference< XDataSeries > > > aSeries(1); 146 aSeries[0] = ContainerToSequence( aSeriesVec ); 147 return InterpretedData( aSeries, xCategories ); 148 } 149 150 InterpretedData SAL_CALL DataInterpreter::reinterpretDataSeries( 151 const InterpretedData& aInterpretedData ) 152 { 153 InterpretedData aResult( aInterpretedData ); 154 155 sal_Int32 i=0; 156 Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); 157 const sal_Int32 nCount = aSeries.getLength(); 158 for( ; i<nCount; ++i ) 159 { 160 try 161 { 162 Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW ); 163 Sequence< Reference< data::XLabeledDataSequence > > aNewSequences; 164 165 // values-y 166 Reference< data::XLabeledDataSequence > xValuesY( 167 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false )); 168 // re-use values-... as values-y 169 if( ! xValuesY.is()) 170 { 171 xValuesY.set( 172 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values"), true )); 173 if( xValuesY.is()) 174 SetRole( xValuesY->getValues(), C2U("values-y")); 175 } 176 if( xValuesY.is()) 177 { 178 aNewSequences.realloc(1); 179 aNewSequences[0] = xValuesY; 180 } 181 182 Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences()); 183 if( aSeqs.getLength() != aNewSequences.getLength() ) 184 { 185 #if OSL_DEBUG_LEVEL > 1 186 sal_Int32 j=0; 187 for( ; j<aSeqs.getLength(); ++j ) 188 { 189 OSL_ENSURE( aSeqs[j] == xValuesY, "All sequences should be used" ); 190 } 191 #endif 192 Reference< data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY_THROW ); 193 xSink->setData( aNewSequences ); 194 } 195 } 196 catch( uno::Exception & ex ) 197 { 198 ASSERT_EXCEPTION( ex ); 199 } 200 } 201 202 return aResult; 203 } 204 205 // criterion: all series must have exactly one data::XLabeledDataSequence 206 sal_Bool SAL_CALL DataInterpreter::isDataCompatible( 207 const chart2::InterpretedData& aInterpretedData ) 208 { 209 Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); 210 for( sal_Int32 i=0; i<aSeries.getLength(); ++i ) 211 { 212 try 213 { 214 Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW ); 215 Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences()); 216 if( aSeq.getLength() != 1 ) 217 return sal_False; 218 } 219 catch( uno::Exception & ex ) 220 { 221 ASSERT_EXCEPTION( ex ); 222 } 223 } 224 225 return sal_True; 226 } 227 228 namespace 229 { 230 231 struct lcl_LabeledSequenceEquals : public unary_function< Reference< data::XLabeledDataSequence >, bool > 232 { 233 lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) : 234 m_bHasLabels ( false ), 235 m_bHasValues ( false ) 236 { 237 if( xLSeqToCmp.is()) 238 { 239 Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues()); 240 if( xSeq.is()) 241 { 242 m_bHasValues = true; 243 m_aValuesRangeRep = xSeq->getSourceRangeRepresentation(); 244 } 245 246 xSeq.set( xLSeqToCmp->getLabel()); 247 if( xSeq.is()) 248 { 249 m_bHasLabels = true; 250 m_aLabelRangeRep = xSeq->getSourceRangeRepresentation(); 251 } 252 } 253 } 254 255 bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq ) 256 { 257 if( ! xSeq.is()) 258 return false; 259 260 Reference< data::XDataSequence > xSeqValues( xSeq->getValues() ); 261 Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() ); 262 bool bHasValues = xSeqValues.is(); 263 bool bHasLabels = xSeqLabels.is(); 264 265 return ( ( (m_bHasValues == bHasValues) && 266 (!bHasValues || m_aValuesRangeRep.equals( xSeqValues->getSourceRangeRepresentation())) ) && 267 ( (m_bHasLabels == bHasLabels) && 268 (!bHasLabels || m_aLabelRangeRep.equals( xSeqLabels->getSourceRangeRepresentation())) ) 269 ); 270 } 271 272 private: 273 bool m_bHasLabels; 274 bool m_bHasValues; 275 OUString m_aValuesRangeRep; 276 OUString m_aLabelRangeRep; 277 }; 278 279 } // anonymous namespace 280 281 Reference< data::XDataSource > SAL_CALL DataInterpreter::mergeInterpretedData( 282 const InterpretedData& aInterpretedData ) 283 { 284 vector< Reference< data::XLabeledDataSequence > > aResultVec; 285 aResultVec.reserve( aInterpretedData.Series.getLength() + 286 1 // categories 287 ); 288 289 if( aInterpretedData.Categories.is()) 290 aResultVec.push_back( aInterpretedData.Categories ); 291 292 Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); 293 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx ) 294 { 295 try 296 { 297 Reference< data::XDataSource > xSrc( aSeries[nSeriesIdx], uno::UNO_QUERY_THROW ); 298 Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences()); 299 300 // add all sequences of data series 301 for( sal_Int32 nSeqIdx=0; nSeqIdx<aSeq.getLength(); ++nSeqIdx ) 302 { 303 Reference< data::XLabeledDataSequence > xAdd( aSeq[nSeqIdx] ); 304 305 // only add if sequence is not yet in the result 306 if( find_if( aResultVec.begin(), aResultVec.end(), 307 lcl_LabeledSequenceEquals( xAdd )) == aResultVec.end()) 308 { 309 aResultVec.push_back( xAdd ); 310 } 311 } 312 } 313 catch( uno::Exception & ex ) 314 { 315 ASSERT_EXCEPTION( ex ); 316 } 317 } 318 319 return Reference< data::XDataSource >( DataSourceHelper::createDataSource( ContainerToSequence( aResultVec ) ) ); 320 } 321 322 // convenience methods 323 324 OUString DataInterpreter::GetRole( const Reference< data::XDataSequence > & xSeq ) 325 { 326 OUString aResult; 327 if( ! xSeq.is()) 328 return aResult; 329 330 try 331 { 332 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); 333 xProp->getPropertyValue( C2U("Role")) >>= aResult; 334 } 335 catch( uno::Exception & ex ) 336 { 337 ASSERT_EXCEPTION( ex ); 338 } 339 return aResult; 340 } 341 342 void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole ) 343 { 344 if( ! xSeq.is()) 345 return; 346 try 347 { 348 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); 349 xProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole )); 350 } 351 catch( uno::Exception & ex ) 352 { 353 ASSERT_EXCEPTION( ex ); 354 } 355 } 356 357 uno::Any DataInterpreter::GetProperty( 358 const Sequence< beans::PropertyValue > & aArguments, 359 const OUString & rName ) 360 { 361 for( sal_Int32 i=aArguments.getLength(); i--; ) 362 { 363 if( aArguments[i].Name.equals( rName )) 364 return aArguments[i].Value; 365 } 366 return uno::Any(); 367 } 368 369 bool DataInterpreter::HasCategories( 370 const Sequence< beans::PropertyValue > & rArguments, 371 const Sequence< Reference< data::XLabeledDataSequence > > & rData ) 372 { 373 bool bHasCategories = false; 374 375 if( rArguments.getLength() > 0 ) 376 GetProperty( rArguments, C2U(("HasCategories"))) >>= bHasCategories; 377 378 for( sal_Int32 nLSeqIdx=0; ! bHasCategories && nLSeqIdx<rData.getLength(); ++nLSeqIdx ) 379 bHasCategories = ( rData[nLSeqIdx].is() && 380 GetRole( rData[nLSeqIdx]->getValues()).equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("categories"))); 381 382 return bHasCategories; 383 } 384 385 bool DataInterpreter::UseCategoriesAsX( const Sequence< beans::PropertyValue > & rArguments ) 386 { 387 bool bUseCategoriesAsX = true; 388 if( rArguments.getLength() > 0 ) 389 GetProperty( rArguments, C2U(("UseCategoriesAsX"))) >>= bUseCategoriesAsX; 390 return bUseCategoriesAsX; 391 } 392 393 // ------------------------------------------------------------ 394 395 Sequence< OUString > DataInterpreter::getSupportedServiceNames_Static() 396 { 397 Sequence< OUString > aServices( 1 ); 398 aServices[0] = C2U( "com.sun.star.chart2.DataInterpreter" ); 399 return aServices; 400 } 401 402 // implement XServiceInfo methods basing upon getSupportedServiceNames_Static 403 APPHELPER_XSERVICEINFO_IMPL( DataInterpreter, C2U("com.sun.star.comp.chart2.DataInterpreter")); 404 405 } // namespace chart 406 407 #if OSL_DEBUG_LEVEL > 1 408 namespace 409 { 410 411 void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource ) 412 { 413 if( ! xSource.is()) 414 return; 415 416 OSL_TRACE( "DataSource in DataInterpreter:" ); 417 Sequence< Reference< data::XLabeledDataSequence > > aSequences( xSource->getDataSequences()); 418 Reference< beans::XPropertySet > xProp; 419 OUString aId; 420 const sal_Int32 nMax = aSequences.getLength(); 421 for( sal_Int32 k = 0; k < nMax; ++k ) 422 { 423 if( aSequences[k].is()) 424 { 425 OUString aSourceRepr(C2U("<none>")); 426 if( aSequences[k]->getValues().is()) 427 aSourceRepr = aSequences[k]->getValues()->getSourceRangeRepresentation(); 428 xProp.set( aSequences[k]->getValues(), uno::UNO_QUERY ); 429 if( xProp.is() && 430 ( xProp->getPropertyValue( C2U( "Role" )) >>= aId )) 431 { 432 OSL_TRACE( " <data sequence %d> Role: %s, Source: %s", k, U2C( aId ), U2C( aSourceRepr )); 433 } 434 else 435 { 436 OSL_TRACE( " <data sequence %d> unknown Role, Source: %s", k, U2C( aSourceRepr ) ); 437 } 438 439 aSourceRepr = C2U("<none>"); 440 if( aSequences[k]->getLabel().is()) 441 aSourceRepr = OUString( aSequences[k]->getLabel()->getSourceRangeRepresentation()); 442 xProp.set( aSequences[k]->getLabel(), uno::UNO_QUERY ); 443 if( xProp.is() && 444 ( xProp->getPropertyValue( C2U( "Role" )) >>= aId )) 445 { 446 OSL_TRACE( " <data sequence label %d> Role: %s, Source: %s", k, U2C( aId ), U2C( aSourceRepr )); 447 } 448 else 449 { 450 OSL_TRACE( " <data sequence label %d> unknown Role, Source: %s", k, U2C( aSourceRepr ) ); 451 } 452 } 453 } 454 } 455 456 } 457 #endif 458