| /************************************************************** | 
 |  *  | 
 |  * Licensed to the Apache Software Foundation (ASF) under one | 
 |  * or more contributor license agreements.  See the NOTICE file | 
 |  * distributed with this work for additional information | 
 |  * regarding copyright ownership.  The ASF licenses this file | 
 |  * to you under the Apache License, Version 2.0 (the | 
 |  * "License"); you may not use this file except in compliance | 
 |  * with the License.  You may obtain a copy of the License at | 
 |  *  | 
 |  *   http://www.apache.org/licenses/LICENSE-2.0 | 
 |  *  | 
 |  * Unless required by applicable law or agreed to in writing, | 
 |  * software distributed under the License is distributed on an | 
 |  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 |  * KIND, either express or implied.  See the License for the | 
 |  * specific language governing permissions and limitations | 
 |  * under the License. | 
 |  *  | 
 |  *************************************************************/ | 
 |  | 
 |  | 
 |  | 
 | // MARKER(update_precomp.py): autogen include statement, do not remove | 
 | #include "precompiled_chart2.hxx" | 
 |  | 
 | #include "BubbleDataInterpreter.hxx" | 
 | #include "DataSeries.hxx" | 
 | #include "macros.hxx" | 
 | #include "DataSeriesHelper.hxx" | 
 | #include "CommonConverters.hxx" | 
 | #include "ContainerHelper.hxx" | 
 | #include <com/sun/star/beans/XPropertySet.hpp> | 
 | #include <com/sun/star/chart2/data/XDataSink.hpp> | 
 | #include <com/sun/star/util/XCloneable.hpp> | 
 |  | 
 | using namespace ::com::sun::star; | 
 | using namespace ::com::sun::star::chart2; | 
 | using namespace ::std; | 
 |  | 
 | using ::com::sun::star::uno::Reference; | 
 | using ::com::sun::star::uno::Sequence; | 
 | using ::rtl::OUString; | 
 |  | 
 | namespace chart | 
 | { | 
 |  | 
 | BubbleDataInterpreter::BubbleDataInterpreter( | 
 |     const uno::Reference< uno::XComponentContext > & xContext ) : | 
 |         DataInterpreter( xContext ) | 
 | { | 
 | } | 
 |  | 
 | BubbleDataInterpreter::~BubbleDataInterpreter() | 
 | { | 
 | } | 
 |  | 
 | // ____ XDataInterpreter ____ | 
 | chart2::InterpretedData SAL_CALL BubbleDataInterpreter::interpretDataSource( | 
 |     const Reference< chart2::data::XDataSource >& xSource, | 
 |     const Sequence< beans::PropertyValue >& aArguments, | 
 |     const Sequence< Reference< XDataSeries > >& aSeriesToReUse ) | 
 |     throw (uno::RuntimeException) | 
 | { | 
 |     if( ! xSource.is()) | 
 |         return InterpretedData(); | 
 |  | 
 |     Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() ); | 
 |  | 
 |     Reference< data::XLabeledDataSequence > xValuesX; | 
 |     vector< Reference< data::XLabeledDataSequence > > aYValuesVector; | 
 |     vector< Reference< data::XLabeledDataSequence > > aSizeValuesVector; | 
 |  | 
 |     Reference< data::XLabeledDataSequence > xCategories; | 
 |     bool bHasCategories = HasCategories( aArguments, aData ); | 
 |     bool bUseCategoriesAsX = UseCategoriesAsX( aArguments ); | 
 |      | 
 |     bool bSetXValues = false; | 
 |     sal_Int32 nDataSeqCount = aData.getLength(); | 
 |  | 
 |     bSetXValues = bHasCategories ? ( (nDataSeqCount-1) > 2 && (nDataSeqCount-1) % 2 != 0 ) | 
 |                                  :( nDataSeqCount > 2 && nDataSeqCount % 2 != 0 ); | 
 |  | 
 |     bool bCategoriesUsed = false;   | 
 |     bool bNextIsYValues = bHasCategories ? nDataSeqCount>2 : nDataSeqCount>1; | 
 |     for( sal_Int32 nDataIdx = 0; nDataIdx < nDataSeqCount; ++nDataIdx ) | 
 |     { | 
 |         try | 
 |         { | 
 |             if( bHasCategories && !bCategoriesUsed ) | 
 |             { | 
 |                 xCategories.set( aData[nDataIdx] ); | 
 |                 if( xCategories.is()) | 
 |                 { | 
 |                     SetRole( xCategories->getValues(), C2U("categories")); | 
 |                     if( bUseCategoriesAsX ) | 
 |                     { | 
 |                         bSetXValues = false; | 
 |                         bNextIsYValues = nDataSeqCount > 2; | 
 |                     } | 
 |                 } | 
 |                 bCategoriesUsed = true; | 
 |             } | 
 |             else if( !xValuesX.is() && bSetXValues ) | 
 |             { | 
 |                 xValuesX.set( aData[nDataIdx] ); | 
 |                 if( xValuesX.is()) | 
 |                     SetRole( xValuesX->getValues(), C2U("values-x")); | 
 |             } | 
 |             else if( bNextIsYValues ) | 
 |             { | 
 |                 aYValuesVector.push_back( aData[nDataIdx] ); | 
 |                 if( aData[nDataIdx].is()) | 
 |                     SetRole( aData[nDataIdx]->getValues(), C2U("values-y")); | 
 |                 bNextIsYValues = false; | 
 |             } | 
 |             else if( !bNextIsYValues ) | 
 |             { | 
 |                 aSizeValuesVector.push_back( aData[nDataIdx] ); | 
 |                 if( aData[nDataIdx].is()) | 
 |                     SetRole( aData[nDataIdx]->getValues(), C2U("values-size")); | 
 |                 bNextIsYValues = (nDataSeqCount-(nDataIdx+1)) >= 2;//two or more left | 
 |             } | 
 |         } | 
 |         catch( uno::Exception & ex ) | 
 |         { | 
 |             ASSERT_EXCEPTION( ex ); | 
 |         } | 
 |     } | 
 |  | 
 |     // create DataSeries | 
 |     sal_Int32 nSeriesIndex = 0; | 
 |     vector< Reference< XDataSeries > > aSeriesVec; | 
 |     aSeriesVec.reserve( aSizeValuesVector.size()); | 
 |  | 
 |     Reference< data::XLabeledDataSequence > xClonedXValues = xValuesX; | 
 |     Reference< util::XCloneable > xCloneableX( xValuesX, uno::UNO_QUERY ); | 
 |  | 
 |     for( size_t nN = 0; nN < aSizeValuesVector.size(); ++nN, ++nSeriesIndex ) | 
 |     { | 
 |         vector< Reference< data::XLabeledDataSequence > > aNewData; | 
 |         if( xValuesX.is() ) | 
 |         { | 
 |             if( nN > 0 && xCloneableX.is() ) | 
 |                 xClonedXValues.set( xCloneableX->createClone(), uno::UNO_QUERY ); | 
 |             aNewData.push_back( xClonedXValues ); | 
 |         } | 
 |         if( aYValuesVector.size() > nN ) | 
 |             aNewData.push_back( aYValuesVector[nN] );  | 
 |         if( aSizeValuesVector.size() > nN ) | 
 |             aNewData.push_back( aSizeValuesVector[nN] ); | 
 |  | 
 |         Reference< XDataSeries > xSeries; | 
 |         if( nSeriesIndex < aSeriesToReUse.getLength()) | 
 |             xSeries.set( aSeriesToReUse[nSeriesIndex] ); | 
 |         else | 
 |             xSeries.set( new DataSeries( GetComponentContext() ) ); | 
 |         OSL_ASSERT( xSeries.is() ); | 
 |         Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY ); | 
 |         OSL_ASSERT( xSink.is() ); | 
 |         xSink->setData( ContainerHelper::ContainerToSequence( aNewData ) ); | 
 |  | 
 |         aSeriesVec.push_back( xSeries ); | 
 |     } | 
 |  | 
 |     Sequence< Sequence< Reference< XDataSeries > > > aSeries(1); | 
 |     aSeries[0] = ContainerHelper::ContainerToSequence( aSeriesVec ); | 
 |     return InterpretedData( aSeries, xCategories ); | 
 | } | 
 |  | 
 | chart2::InterpretedData SAL_CALL BubbleDataInterpreter::reinterpretDataSeries( | 
 |     const chart2::InterpretedData& aInterpretedData ) | 
 |     throw (uno::RuntimeException) | 
 | { | 
 |     InterpretedData aResult( aInterpretedData ); | 
 |  | 
 |     sal_Int32 i=0; | 
 |     Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); | 
 |     const sal_Int32 nCount = aSeries.getLength(); | 
 |     for( ; i<nCount; ++i ) | 
 |     { | 
 |         try | 
 |         { | 
 |             Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW ); | 
 |             Sequence< Reference< data::XLabeledDataSequence > > aNewSequences; | 
 |  | 
 | 			Reference< data::XLabeledDataSequence > xValuesSize( | 
 |                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-size"), false )); | 
 |             Reference< data::XLabeledDataSequence > xValuesY( | 
 |                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false )); | 
 |             Reference< data::XLabeledDataSequence > xValuesX( | 
 |                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-x"), false )); | 
 |  | 
 |             if( ! xValuesX.is() || | 
 |                 ! xValuesY.is() || | 
 | 				! xValuesSize.is() ) | 
 |             { | 
 |                 vector< Reference< data::XLabeledDataSequence > > aValueSeqVec( | 
 |                     DataSeriesHelper::getAllDataSequencesByRole( | 
 |                         xSeriesSource->getDataSequences(), C2U("values"), true )); | 
 |                 if( xValuesX.is()) | 
 |                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesX )); | 
 |                 if( xValuesY.is()) | 
 |                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesY )); | 
 | 				if( xValuesSize.is()) | 
 |                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesSize )); | 
 |  | 
 |                 size_t nIndex = 0; | 
 |  | 
 |                 if( ! xValuesSize.is() && | 
 |                     aValueSeqVec.size() > nIndex ) | 
 |                 { | 
 |                     xValuesSize.set( aValueSeqVec[nIndex++] ); | 
 |                     if( xValuesSize.is()) | 
 |                         SetRole( xValuesSize->getValues(), C2U("values-size")); | 
 |                 } | 
 |  | 
 |                 if( ! xValuesY.is() && | 
 |                     aValueSeqVec.size() > nIndex ) | 
 |                 { | 
 |                     xValuesY.set( aValueSeqVec[nIndex++] ); | 
 |                     if( xValuesY.is()) | 
 |                         SetRole( xValuesY->getValues(), C2U("values-y")); | 
 |                 } | 
 |  | 
 |                 if( ! xValuesX.is() && | 
 |                     aValueSeqVec.size() > nIndex ) | 
 |                 { | 
 |                     xValuesX.set( aValueSeqVec[nIndex++] ); | 
 |                     if( xValuesX.is()) | 
 |                         SetRole( xValuesY->getValues(), C2U("values-x")); | 
 |                 } | 
 |             } | 
 |             if( xValuesSize.is()) | 
 |             { | 
 | 				if( xValuesY.is() ) | 
 | 				{ | 
 | 				    if( xValuesX.is() ) | 
 | 					{ | 
 | 					    aNewSequences.realloc(3); | 
 |                         aNewSequences[0] = xValuesX; | 
 |                         aNewSequences[1] = xValuesY; | 
 | 						aNewSequences[2] = xValuesSize; | 
 | 					} | 
 | 					else | 
 | 					{ | 
 | 					    aNewSequences.realloc(2); | 
 |                         aNewSequences[0] = xValuesY; | 
 |                         aNewSequences[1] = xValuesSize; | 
 | 					} | 
 | 				} | 
 |                 else | 
 |                 { | 
 |                     aNewSequences.realloc(1); | 
 |                     aNewSequences[0] = xValuesSize; | 
 |                 } | 
 |             } | 
 |  | 
 |             Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences()); | 
 |             if( aSeqs.getLength() != aNewSequences.getLength() ) | 
 |             { | 
 | #if OSL_DEBUG_LEVEL > 1 | 
 |                 sal_Int32 j=0; | 
 |                 for( ; j<aSeqs.getLength(); ++j ) | 
 |                 { | 
 |                     OSL_ENSURE( aSeqs[j] == xValuesY || aSeqs[j] == xValuesX || aSeqs[j] == xValuesSize, "All sequences should be used" ); | 
 |                 } | 
 | #endif | 
 |                 Reference< data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY_THROW ); | 
 |                 xSink->setData( aNewSequences ); | 
 |             } | 
 |         } | 
 |         catch( uno::Exception & ex ) | 
 |         { | 
 |             ASSERT_EXCEPTION( ex ); | 
 |         } | 
 |     } | 
 |  | 
 |     return aResult; | 
 | } | 
 |  | 
 | sal_Bool SAL_CALL BubbleDataInterpreter::isDataCompatible( | 
 |     const chart2::InterpretedData& aInterpretedData ) | 
 |     throw (uno::RuntimeException) | 
 | { | 
 |     Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); | 
 |     for( sal_Int32 i=0; i<aSeries.getLength(); ++i ) | 
 |     { | 
 |         try | 
 |         { | 
 |             Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW ); | 
 |             Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences()); | 
 |             if( aSeq.getLength() != 3 ) | 
 |                 return sal_False; | 
 |         } | 
 |         catch( uno::Exception & ex ) | 
 |         { | 
 |             ASSERT_EXCEPTION( ex ); | 
 |         } | 
 |     } | 
 |  | 
 |     return sal_True; | 
 | } | 
 |  | 
 | } // namespace chart |