| /************************************************************** |
| * |
| * 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 "ChartTypeTemplate.hxx" |
| #include "PropertyHelper.hxx" |
| #include "macros.hxx" |
| #include "DataSeriesHelper.hxx" |
| #include "DataInterpreter.hxx" |
| #include "CommonConverters.hxx" |
| #include "ContainerHelper.hxx" |
| #include "ChartTypeHelper.hxx" |
| |
| #include "CartesianCoordinateSystem.hxx" |
| #include "AxisHelper.hxx" |
| #include "LegendHelper.hxx" |
| #include "DiagramHelper.hxx" |
| #include "ChartDebugTrace.hxx" |
| #include "AxisIndexDefines.hxx" |
| #include <cppuhelper/component_context.hxx> |
| #include <com/sun/star/chart/ChartSolidType.hpp> |
| #include <com/sun/star/chart2/AxisType.hpp> |
| #include <com/sun/star/chart2/XDataSeriesContainer.hpp> |
| #include <com/sun/star/chart2/XChartTypeContainer.hpp> |
| #include <com/sun/star/chart2/AxisType.hpp> |
| |
| #include <algorithm> |
| #include <iterator> |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::chart2; |
| |
| using ::rtl::OUString; |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::uno::Any; |
| |
| // ====================================================================== |
| |
| namespace |
| { |
| |
| void lcl_applyDefaultStyle( |
| const Reference< XDataSeries > & xSeries, |
| sal_Int32 nIndex, |
| const Reference< XDiagram > & xDiagram ) |
| { |
| // @deprecated: correct default color should be found by view without |
| // setting color as hard attribute |
| if( xSeries.is() && xDiagram.is()) |
| { |
| Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); |
| Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); |
| if( xSeriesProp.is() && xColorScheme.is() ) |
| xSeriesProp->setPropertyValue( |
| C2U("Color"), |
| uno::makeAny( xColorScheme->getColorByIndex( nIndex ))); |
| } |
| } |
| |
| void lcl_ensureCorrectLabelPlacement( const Reference< beans::XPropertySet >& xProp, const uno::Sequence < sal_Int32 >& rAvailablePlacements ) |
| { |
| sal_Int32 nLabelPlacement=0; |
| if( xProp.is() && (xProp->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement) ) |
| { |
| bool bValid = false; |
| for( sal_Int32 nN = 0; nN < rAvailablePlacements.getLength(); nN++ ) |
| { |
| if( rAvailablePlacements[nN] == nLabelPlacement ) |
| { |
| bValid = true; |
| break; |
| } |
| } |
| if( !bValid ) |
| { |
| uno::Any aNewValue; |
| //otherwise use the first supported one |
| if( rAvailablePlacements.getLength() ) |
| aNewValue <<=rAvailablePlacements[0]; |
| xProp->setPropertyValue( C2U("LabelPlacement"), aNewValue ); |
| } |
| } |
| } |
| |
| void lcl_resetLabelPlacementIfDefault( const Reference< beans::XPropertySet >& xProp, sal_Int32 nDefaultPlacement ) |
| { |
| |
| sal_Int32 nLabelPlacement=0; |
| if( xProp.is() && (xProp->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement) ) |
| { |
| if( nDefaultPlacement == nLabelPlacement ) |
| xProp->setPropertyValue( C2U("LabelPlacement"), uno::Any() ); |
| } |
| } |
| |
| void lcl_ensureCorrectMissingValueTreatment( const Reference< chart2::XDiagram >& xDiagram, const Reference< XChartType >& xChartType ) |
| { |
| Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY ); |
| if( xDiaProp.is() ) |
| { |
| uno::Sequence < sal_Int32 > aAvailableMissingValueTreatment( |
| ::chart::ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) ); |
| |
| if( aAvailableMissingValueTreatment.getLength() ) |
| xDiaProp->setPropertyValue( C2U( "MissingValueTreatment" ), uno::makeAny( aAvailableMissingValueTreatment[0] ) ); |
| else |
| xDiaProp->setPropertyValue( C2U( "MissingValueTreatment" ), uno::Any() ); |
| } |
| } |
| |
| } // anonymous namespace |
| |
| namespace chart |
| { |
| |
| ChartTypeTemplate::ChartTypeTemplate( |
| Reference< uno::XComponentContext > const & xContext, |
| const ::rtl::OUString & rServiceName ) : |
| m_xContext( xContext ), |
| m_aServiceName( rServiceName ) |
| { |
| } |
| |
| ChartTypeTemplate::~ChartTypeTemplate() |
| {} |
| |
| // ____ XChartTypeTemplate ____ |
| uno::Reference< XDiagram > SAL_CALL ChartTypeTemplate::createDiagramByDataSource( |
| const uno::Reference< data::XDataSource >& xDataSource, |
| const uno::Sequence< beans::PropertyValue >& aArguments ) |
| throw (uno::RuntimeException) |
| { |
| Reference< XDiagram > xDia; |
| |
| try |
| { |
| // create diagram |
| xDia.set( |
| GetComponentContext()->getServiceManager()->createInstanceWithContext( |
| C2U( "com.sun.star.chart2.Diagram" ), |
| GetComponentContext() ), |
| uno::UNO_QUERY_THROW ); |
| |
| // modify diagram |
| Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter()); |
| chart2::InterpretedData aData( |
| xInterpreter->interpretDataSource( |
| xDataSource, aArguments, Sequence< Reference< XDataSeries > >() )); |
| |
| Sequence< Sequence< Reference< XDataSeries > > > aSeries( aData.Series ); |
| sal_Int32 i, j, nCount = 0; |
| for( i=0; i<aSeries.getLength(); ++i ) |
| { |
| for( j=0; j<aSeries[i].getLength(); ++j, ++nCount ) |
| lcl_applyDefaultStyle( aSeries[i][j], nCount, xDia ); |
| } |
| |
| Sequence< Reference< XChartType > > aOldChartTypesSeq; |
| FillDiagram( xDia, aData.Series, aData.Categories, aOldChartTypesSeq, true ); |
| } |
| catch( uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| |
| return xDia; |
| } |
| |
| sal_Bool SAL_CALL ChartTypeTemplate::supportsCategories() |
| throw (uno::RuntimeException) |
| { |
| return sal_True; |
| } |
| |
| void SAL_CALL ChartTypeTemplate::changeDiagram( const uno::Reference< XDiagram >& xDiagram ) |
| throw (uno::RuntimeException) |
| { |
| if( ! xDiagram.is()) |
| return; |
| |
| try |
| { |
| Sequence< Sequence< Reference< XDataSeries > > > aSeriesSeq( |
| DiagramHelper::getDataSeriesGroups( xDiagram )); |
| Sequence< Reference< XDataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq )); |
| const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.getLength(); |
| |
| // chart-type specific interpretation of existing data series |
| Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter()); |
| chart2::InterpretedData aData; |
| aData.Series = aSeriesSeq; |
| aData.Categories = DiagramHelper::getCategoriesFromDiagram( xDiagram ); |
| |
| if( xInterpreter->isDataCompatible( aData ) ) |
| { |
| aData = xInterpreter->reinterpretDataSeries( aData ); |
| } |
| else |
| { |
| Reference< data::XDataSource > xSource( xInterpreter->mergeInterpretedData( aData )); |
| // todo: get a "range-union" from the data provider by calling |
| // OUString aRange = getRangeRepresentationByData( xSource ); |
| // xSource.set( getDataByRangeRepresentation( aRange, aParam )); |
| // where aParam == ?? |
| Sequence< beans::PropertyValue > aParam; |
| if( aData.Categories.is()) |
| { |
| aParam.realloc( 1 ); |
| aParam[0] = beans::PropertyValue( C2U("HasCategories"), -1, uno::makeAny( true ), |
| beans::PropertyState_DIRECT_VALUE ); |
| } |
| aData = xInterpreter->interpretDataSource( xSource, aParam, aFlatSeriesSeq ); |
| } |
| aSeriesSeq = aData.Series; |
| |
| sal_Int32 i, j, nIndex = 0; |
| for( i=0; i<aSeriesSeq.getLength(); ++i ) |
| for( j=0; j<aSeriesSeq[i].getLength(); ++j, ++nIndex ) |
| { |
| if( nIndex >= nFormerSeriesCount ) |
| lcl_applyDefaultStyle( aSeriesSeq[i][j], nIndex, xDiagram ); |
| } |
| |
| // remove charttype groups from all coordinate systems |
| Sequence< Reference< XChartType > > aOldChartTypesSeq( |
| DiagramHelper::getChartTypesFromDiagram(xDiagram) ); |
| |
| Reference< XCoordinateSystemContainer > xCoordSysCnt( xDiagram, uno::UNO_QUERY ); |
| OSL_ASSERT( xCoordSysCnt.is()); |
| if( xCoordSysCnt.is()) |
| { |
| Sequence< Reference< XCoordinateSystem > > aCooSysSeq( |
| xCoordSysCnt->getCoordinateSystems()); |
| for( sal_Int32 nCooSysIdx = 0; nCooSysIdx < aCooSysSeq.getLength(); ++nCooSysIdx ) |
| { |
| Reference< XChartTypeContainer > xContainer( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY ); |
| if( xContainer.is() ) |
| xContainer->setChartTypes( Sequence< Reference< XChartType > >() ); |
| } |
| } |
| |
| FillDiagram( xDiagram, aSeriesSeq, aData.Categories, aOldChartTypesSeq, false ); |
| } |
| catch( uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| } |
| |
| void SAL_CALL ChartTypeTemplate::changeDiagramData( |
| const Reference< chart2::XDiagram >& xDiagram, |
| const Reference< chart2::data::XDataSource >& xDataSource, |
| const Sequence< beans::PropertyValue >& aArguments ) |
| throw (uno::RuntimeException) |
| { |
| if( ! (xDiagram.is() && |
| xDataSource.is()) ) |
| return; |
| |
| try |
| { |
| // interpret new data and re-use existing series |
| Sequence< Reference< XDataSeries > > aFlatSeriesSeq( |
| ::chart::ContainerHelper::ContainerToSequence( DiagramHelper::getDataSeriesFromDiagram( xDiagram ))); |
| const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.getLength(); |
| Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter()); |
| chart2::InterpretedData aData = |
| xInterpreter->interpretDataSource( xDataSource, aArguments, aFlatSeriesSeq ); |
| |
| // data series |
| Sequence< Sequence< Reference< XDataSeries > > > aSeriesSeq( aData.Series ); |
| |
| sal_Int32 i, j, nIndex = 0; |
| for( i=0; i<aSeriesSeq.getLength(); ++i ) |
| for( j=0; j<aSeriesSeq[i].getLength(); ++j, ++nIndex ) |
| { |
| if( nIndex >= nFormerSeriesCount ) |
| { |
| lcl_applyDefaultStyle( aSeriesSeq[i][j], nIndex, xDiagram ); |
| applyStyle( aSeriesSeq[i][j], i, j, aSeriesSeq[i].getLength() ); |
| } |
| } |
| |
| // categories |
| DiagramHelper::setCategoriesToDiagram( aData.Categories, xDiagram, true, supportsCategories() ); |
| |
| Sequence< Reference< XChartType > > aChartTypes( |
| DiagramHelper::getChartTypesFromDiagram( xDiagram )); |
| sal_Int32 nMax = ::std::min( aChartTypes.getLength(), aSeriesSeq.getLength()); |
| for( i=0; i<nMax; ++i ) |
| { |
| Reference< XDataSeriesContainer > xDSCnt( aChartTypes[i], uno::UNO_QUERY_THROW ); |
| xDSCnt->setDataSeries( aSeriesSeq[i] ); |
| } |
| #if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL |
| OSL_TRACE( "ChartTypeTemplate::changeDiagramData: Showing Diagram structure" ); |
| OSL_TRACE( "---------------------------------------------------------------" ); |
| debug::ChartDebugTraceDiagram( xDiagram ); |
| #endif |
| } |
| catch( uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| } |
| |
| sal_Bool SAL_CALL ChartTypeTemplate::matchesTemplate( |
| const Reference< chart2::XDiagram >& xDiagram, |
| sal_Bool /* bAdaptProperties */ ) |
| throw (uno::RuntimeException) |
| { |
| sal_Bool bResult = sal_False; |
| |
| if( ! xDiagram.is()) |
| return bResult; |
| |
| try |
| { |
| Reference< XCoordinateSystemContainer > xCooSysCnt( |
| xDiagram, uno::UNO_QUERY_THROW ); |
| Sequence< Reference< XCoordinateSystem > > aCooSysSeq( |
| xCooSysCnt->getCoordinateSystems()); |
| |
| // need to have at least one coordinate system |
| bResult = (aCooSysSeq.getLength() > 0); |
| if( bResult ) |
| { |
| Sequence< Reference< XChartType > > aFormerlyUsedChartTypes; |
| const OUString aChartTypeToMatch( getChartTypeForNewSeries(aFormerlyUsedChartTypes)->getChartType()); |
| const sal_Int32 nDimensionToMatch = getDimension(); |
| for( sal_Int32 nCooSysIdx=0; bResult && (nCooSysIdx < aCooSysSeq.getLength()); ++nCooSysIdx ) |
| { |
| // match dimension |
| bResult = bResult && (aCooSysSeq[nCooSysIdx]->getDimension() == nDimensionToMatch); |
| |
| Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); |
| Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes()); |
| for( sal_Int32 nCTIdx=0; bResult && (nCTIdx < aChartTypeSeq.getLength()); ++nCTIdx ) |
| { |
| // match chart type |
| bResult = bResult && aChartTypeSeq[nCTIdx]->getChartType().equals( aChartTypeToMatch ); |
| bool bFound=false; |
| bool bAmbiguous=false; |
| // match stacking mode |
| bResult = bResult && |
| ( DiagramHelper::getStackModeFromChartType( |
| aChartTypeSeq[nCTIdx], bFound, bAmbiguous, |
| aCooSysSeq[nCooSysIdx] ) |
| == getStackMode( nCTIdx ) ); |
| } |
| } |
| } |
| } |
| catch( uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| |
| return bResult; |
| } |
| |
| Reference< chart2::XDataInterpreter > SAL_CALL ChartTypeTemplate::getDataInterpreter() |
| throw (uno::RuntimeException) |
| { |
| if( ! m_xDataInterpreter.is()) |
| m_xDataInterpreter.set( new DataInterpreter( GetComponentContext() ) ); |
| |
| return m_xDataInterpreter; |
| } |
| |
| void SAL_CALL ChartTypeTemplate::applyStyle( |
| const Reference< chart2::XDataSeries >& xSeries, |
| ::sal_Int32 nChartTypeIndex, |
| ::sal_Int32 /* nSeriesIndex */, |
| ::sal_Int32 /* nSeriesCount */ ) |
| throw (uno::RuntimeException) |
| { |
| // sset stacking mode |
| Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); |
| if( xSeriesProp.is()) |
| { |
| try |
| { |
| StackMode eStackMode = getStackMode( nChartTypeIndex ); |
| const uno::Any aPropValue = uno::makeAny( |
| ( (eStackMode == StackMode_Y_STACKED) || |
| (eStackMode == StackMode_Y_STACKED_PERCENT) ) |
| ? chart2::StackingDirection_Y_STACKING |
| : (eStackMode == StackMode_Z_STACKED ) |
| ? chart2::StackingDirection_Z_STACKING |
| : chart2::StackingDirection_NO_STACKING ); |
| xSeriesProp->setPropertyValue( C2U("StackingDirection"), aPropValue ); |
| |
| //ensure valid label placement |
| { |
| uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( |
| getChartTypeForIndex( nChartTypeIndex ), getDimension(), isSwapXAndY(), xSeries ) ); |
| lcl_ensureCorrectLabelPlacement( xSeriesProp, aAvailablePlacements ); |
| |
| uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; |
| if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) |
| for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) |
| lcl_ensureCorrectLabelPlacement( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), aAvailablePlacements ); |
| } |
| } |
| catch( const uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| } |
| } |
| |
| void SAL_CALL ChartTypeTemplate::applyStyles( const Reference< chart2::XDiagram >& xDiagram ) |
| throw (uno::RuntimeException) |
| { |
| // apply chart-type specific styles, like "symbols on" for example |
| Sequence< Sequence< Reference< XDataSeries > > > aNewSeriesSeq( |
| DiagramHelper::getDataSeriesGroups( xDiagram )); |
| for( sal_Int32 i=0; i<aNewSeriesSeq.getLength(); ++i ) |
| { |
| const sal_Int32 nNumSeries = aNewSeriesSeq[i].getLength(); |
| for( sal_Int32 j=0; j<nNumSeries; ++j ) |
| applyStyle( aNewSeriesSeq[i][j], i, j, nNumSeries ); |
| } |
| |
| //ensure valid empty cell handling (for first chart type...) |
| lcl_ensureCorrectMissingValueTreatment( xDiagram, getChartTypeForIndex( 0 ) ); |
| } |
| |
| void SAL_CALL ChartTypeTemplate::resetStyles( const Reference< chart2::XDiagram >& xDiagram ) |
| throw (uno::RuntimeException) |
| { |
| // reset number format if we had percent stacking on |
| sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT); |
| if( bPercent ) |
| { |
| Sequence< Reference< chart2::XAxis > > aAxisSeq( AxisHelper::getAllAxesOfDiagram( xDiagram ) ); |
| for( sal_Int32 i=0; i<aAxisSeq.getLength(); ++i ) |
| { |
| if( 1== AxisHelper::getDimensionIndexOfAxis( aAxisSeq[i], xDiagram ) ) |
| { |
| Reference< beans::XPropertySet > xAxisProp( aAxisSeq[i], uno::UNO_QUERY ); |
| if( xAxisProp.is()) |
| { |
| // set number format to source format |
| uno::Any aValue( xAxisProp->getPropertyValue(C2U("NumberFormat"))); |
| if( aValue.hasValue()) |
| xAxisProp->setPropertyValue(C2U("NumberFormat"), uno::Any()); |
| } |
| } |
| } |
| } |
| |
| //reset label placement if default |
| { |
| uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); |
| if( xCooSysContainer.is() ) |
| { |
| uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); |
| for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS ) |
| { |
| uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] ); |
| |
| //iterate through all chart types in the current coordinate system |
| uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); |
| OSL_ASSERT( xChartTypeContainer.is()); |
| if( !xChartTypeContainer.is() ) |
| continue; |
| uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); |
| for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT ) |
| { |
| uno::Reference< XChartType > xChartType( aChartTypeList[nT] ); |
| |
| //iterate through all series in this chart type |
| uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); |
| OSL_ASSERT( xDataSeriesContainer.is()); |
| if( !xDataSeriesContainer.is() ) |
| continue; |
| |
| uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); |
| for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS ) |
| { |
| Reference< XDataSeries > xSeries(aSeriesList[nS]); |
| Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); |
| if(!xSeries.is() || !xSeriesProp.is() ) |
| continue; |
| |
| uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( |
| xChartType, getDimension(), isSwapXAndY(), xSeries ) ); |
| if(!aAvailablePlacements.getLength()) |
| continue; |
| |
| sal_Int32 nDefaultPlacement = aAvailablePlacements[0]; |
| |
| lcl_resetLabelPlacementIfDefault( xSeriesProp, nDefaultPlacement ); |
| |
| uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; |
| if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) |
| for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) |
| lcl_resetLabelPlacementIfDefault( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), nDefaultPlacement ); |
| } |
| } |
| } |
| } |
| } |
| |
| return; |
| } |
| |
| // ____ XServiceName ____ |
| ::rtl::OUString SAL_CALL ChartTypeTemplate::getServiceName() |
| throw (uno::RuntimeException) |
| { |
| return m_aServiceName; |
| } |
| |
| // ________________________________________ |
| |
| sal_Int32 ChartTypeTemplate::getDimension() const |
| { |
| return 2; |
| } |
| |
| StackMode ChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const |
| { |
| return StackMode_NONE; |
| } |
| |
| bool ChartTypeTemplate::isSwapXAndY() const |
| { |
| return false; |
| } |
| |
| // ________________________________________ |
| |
| void ChartTypeTemplate::createCoordinateSystems( |
| const Reference< chart2::XCoordinateSystemContainer > & xOutCooSysCnt ) |
| { |
| if( ! xOutCooSysCnt.is()) |
| return; |
| Sequence< Reference< XChartType > > aFormerlyUsedChartTypes; |
| Reference< XChartType > xChartType( getChartTypeForNewSeries(aFormerlyUsedChartTypes)); |
| if( ! xChartType.is()) |
| return; |
| Reference< XCoordinateSystem > xCooSys( xChartType->createCoordinateSystem( getDimension())); |
| if( ! xCooSys.is()) |
| { |
| // chart type wants no coordinate systems |
| xOutCooSysCnt->setCoordinateSystems( Sequence< Reference< XCoordinateSystem > >()); |
| return; |
| } |
| // #i69680# make grid of first y-axis visible (was in the CooSys CTOR before) |
| if( xCooSys->getDimension() >= 2 ) |
| { |
| Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1, 0 )); |
| if( xAxis.is()) |
| AxisHelper::makeGridVisible( xAxis->getGridProperties() ); |
| } |
| |
| Sequence< Reference< XCoordinateSystem > > aCoordinateSystems( |
| xOutCooSysCnt->getCoordinateSystems()); |
| |
| if( aCoordinateSystems.getLength()) |
| { |
| bool bOk = true; |
| for( sal_Int32 i=0; bOk && i<aCoordinateSystems.getLength(); ++i ) |
| bOk = bOk && ( xCooSys->getCoordinateSystemType().equals( aCoordinateSystems[i]->getCoordinateSystemType()) && |
| (xCooSys->getDimension() == aCoordinateSystems[i]->getDimension()) ); |
| // coordinate systems are ok |
| if( bOk ) |
| return; |
| // there are coordinate systems but they do not fit. So overwrite them. |
| } |
| |
| //copy as much info from former coordinate system as possible: |
| if( aCoordinateSystems.getLength() ) |
| { |
| Reference< XCoordinateSystem > xOldCooSys( aCoordinateSystems[0] ); |
| sal_Int32 nMaxDimensionCount = std::min( xCooSys->getDimension(), xOldCooSys->getDimension() ); |
| |
| for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nMaxDimensionCount; nDimensionIndex++) |
| { |
| const sal_Int32 nMaximumAxisIndex = xOldCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); |
| for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) |
| { |
| uno::Reference< XAxis > xAxis( xOldCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); |
| if( xAxis.is()) |
| { |
| xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex ); |
| } |
| } |
| } |
| } |
| |
| // set new coordinate systems |
| aCoordinateSystems.realloc( 1 ); |
| aCoordinateSystems[0] = xCooSys; |
| |
| xOutCooSysCnt->setCoordinateSystems( aCoordinateSystems ); |
| } |
| |
| void ChartTypeTemplate::adaptScales( |
| const Sequence< Reference< chart2::XCoordinateSystem > > & aCooSysSeq, |
| const Reference< data::XLabeledDataSequence > & xCategories //@todo: in future there may be more than one sequence of categories (e.g. charttype with categories at x and y axis ) |
| ) |
| { |
| bool bSupportsCategories( supportsCategories() ); |
| for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) |
| { |
| try |
| { |
| Reference< XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIdx] ); |
| if( !xCooSys.is() ) |
| continue; |
| |
| // attach categories to first axis |
| sal_Int32 nDim( xCooSys->getDimension()); |
| if( nDim > 0 ) |
| { |
| const sal_Int32 nDimensionX = 0; |
| const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionX); |
| for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) |
| { |
| Reference< XAxis > xAxis( xCooSys->getAxisByDimension(nDimensionX,nI) ); |
| if( xAxis.is()) |
| { |
| ScaleData aData( xAxis->getScaleData() ); |
| aData.Categories = xCategories; |
| if(bSupportsCategories) |
| { |
| |
| Reference< XChartType > xChartType( getChartTypeForNewSeries(Sequence< Reference< XChartType > >() )); |
| bool bSupportsDates = ::chart::ChartTypeHelper::isSupportingDateAxis( xChartType, 2, nDimensionX ); |
| if( aData.AxisType != AxisType::CATEGORY && ( aData.AxisType != AxisType::DATE || !bSupportsDates) ) |
| { |
| aData.AxisType = AxisType::CATEGORY; |
| aData.AutoDateAxis = true; |
| AxisHelper::removeExplicitScaling( aData ); |
| } |
| } |
| else |
| aData.AxisType = AxisType::REALNUMBER; |
| |
| xAxis->setScaleData( aData ); |
| } |
| } |
| } |
| // set percent stacking mode at second axis |
| if( nDim > 1 ) |
| { |
| const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(1); |
| for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) |
| { |
| Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI )); |
| if( xAxis.is()) |
| { |
| sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT); |
| chart2::ScaleData aScaleData = xAxis->getScaleData(); |
| |
| if( bPercent != (aScaleData.AxisType==AxisType::PERCENT) ) |
| { |
| if( bPercent ) |
| aScaleData.AxisType = AxisType::PERCENT; |
| else |
| aScaleData.AxisType = AxisType::REALNUMBER; |
| xAxis->setScaleData( aScaleData ); |
| } |
| } |
| } |
| } |
| } |
| catch( const uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| } |
| } |
| |
| void ChartTypeTemplate::adaptDiagram( const Reference< XDiagram > & /* xDiagram */ ) |
| { |
| return; |
| } |
| |
| void ChartTypeTemplate::createAxes( |
| const Sequence< Reference< XCoordinateSystem > > & rCoordSys ) |
| { |
| //create missing axes |
| if( rCoordSys.getLength() > 0 ) |
| { |
| sal_Int32 nCooSysIdx = 0; |
| Reference< XCoordinateSystem > xCooSys( rCoordSys[nCooSysIdx] ); |
| if(!xCooSys.is()) |
| return; |
| |
| //create main axis in first coordinate system |
| sal_Int32 nDimCount = xCooSys->getDimension(); |
| sal_Int32 nDim=0; |
| for( nDim=0; nDim<nDimCount; ++nDim ) |
| { |
| sal_Int32 nAxisCount = getAxisCountByDimension( nDim ); |
| if( nDim == 1 && |
| nAxisCount < 2 && AxisHelper::isSecondaryYAxisNeeded( xCooSys )) |
| nAxisCount = 2; |
| for( sal_Int32 nAxisIndex = 0; nAxisIndex < nAxisCount; ++nAxisIndex ) |
| { |
| Reference< XAxis > xAxis = AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ); |
| if( !xAxis.is()) |
| { |
| // create and add axis |
| xAxis.set( AxisHelper::createAxis( |
| nDim, nAxisIndex, xCooSys, GetComponentContext() )); |
| } |
| } |
| } |
| } |
| } |
| |
| void ChartTypeTemplate::adaptAxes( |
| const Sequence< Reference< XCoordinateSystem > > & rCoordSys ) |
| { |
| //adapt properties of exsisting axes and remove superfluous axes |
| |
| if( rCoordSys.getLength() > 0 ) |
| { |
| for( sal_Int32 nCooSysIdx=0; nCooSysIdx < rCoordSys.getLength(); ++nCooSysIdx ) |
| { |
| Reference< XCoordinateSystem > xCooSys( rCoordSys[nCooSysIdx] ); |
| if( !xCooSys.is() ) |
| continue; |
| sal_Int32 nDimCount = xCooSys->getDimension(); |
| for( sal_Int32 nDim=0; nDim<nDimCount; ++nDim ) |
| { |
| sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension( nDim ); |
| for( sal_Int32 nAxisIndex=0; nAxisIndex<=nMaxAxisIndex; nAxisIndex++ ) |
| { |
| Reference< XAxis > xAxis( AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ) ); |
| if( !xAxis.is() ) |
| continue; |
| |
| if( nAxisIndex == MAIN_AXIS_INDEX || nAxisIndex == SECONDARY_AXIS_INDEX ) |
| { |
| // adapt scales |
| sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT); |
| if( bPercent && nDim == 1 ) |
| { |
| Reference< beans::XPropertySet > xAxisProp( xAxis, uno::UNO_QUERY ); |
| if( xAxisProp.is()) |
| { |
| // set number format to source format |
| uno::Any aValue( xAxisProp->getPropertyValue(C2U("NumberFormat"))); |
| if( aValue.hasValue()) |
| xAxisProp->setPropertyValue(C2U("NumberFormat"), uno::Any()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| sal_Int32 ChartTypeTemplate::getAxisCountByDimension( sal_Int32 nDimension ) |
| { |
| return (nDimension < getDimension()) ? 1 : 0; |
| } |
| |
| void ChartTypeTemplate::FillDiagram( |
| const Reference< XDiagram >& xDiagram, |
| const Sequence< Sequence< Reference< XDataSeries > > >& aSeriesSeq, |
| Reference< data::XLabeledDataSequence > xCategories, |
| const Sequence< Reference< XChartType > >& aOldChartTypesSeq, |
| bool /* bCreate */ ) |
| { |
| adaptDiagram( xDiagram ); |
| |
| try |
| { |
| // create coordinate systems and scales |
| Reference< XCoordinateSystemContainer > xCoordSysCnt( xDiagram, uno::UNO_QUERY_THROW ); |
| createCoordinateSystems( xCoordSysCnt ); |
| Sequence< Reference< XCoordinateSystem > > aCoordinateSystems( xCoordSysCnt->getCoordinateSystems()); |
| createAxes( aCoordinateSystems ); |
| adaptAxes( aCoordinateSystems ); |
| adaptScales( aCoordinateSystems, xCategories ); |
| |
| // chart types |
| createChartTypes( aSeriesSeq, aCoordinateSystems, aOldChartTypesSeq ); |
| applyStyles( xDiagram ); |
| } |
| catch( const uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| |
| #if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL |
| OSL_TRACE( "ChartTypeTemplate::FillDiagram: Showing Diagram structure" ); |
| OSL_TRACE( "---------------------------------------------------------" ); |
| debug::ChartDebugTraceDiagram( xDiagram ); |
| #endif |
| } |
| |
| void ChartTypeTemplate::createChartTypes( |
| const Sequence< Sequence< Reference< XDataSeries > > > & aSeriesSeq, |
| const Sequence< Reference< XCoordinateSystem > > & rCoordSys, |
| const Sequence< Reference< XChartType > >& aOldChartTypesSeq ) |
| { |
| if( rCoordSys.getLength() == 0 || |
| ! rCoordSys[0].is() ) |
| return; |
| |
| try |
| { |
| sal_Int32 nCooSysIdx=0; |
| Reference< XChartType > xCT; |
| if( aSeriesSeq.getLength() == 0 ) |
| { |
| // we need a new chart type |
| xCT.set( getChartTypeForNewSeries( aOldChartTypesSeq )); |
| Reference< XChartTypeContainer > xCTCnt( rCoordSys[nCooSysIdx], uno::UNO_QUERY_THROW ); |
| Sequence< Reference< XChartType > > aCTSeq( xCTCnt->getChartTypes()); |
| aCTSeq.realloc( 1 ); |
| aCTSeq[0] = xCT; |
| xCTCnt->setChartTypes( aCTSeq ); |
| } |
| else |
| { |
| for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx ) |
| { |
| if( nSeriesIdx == nCooSysIdx ) |
| { |
| // we need a new chart type |
| xCT.set( getChartTypeForNewSeries( aOldChartTypesSeq )); |
| Reference< XChartTypeContainer > xCTCnt( rCoordSys[nCooSysIdx], uno::UNO_QUERY_THROW ); |
| Sequence< Reference< XChartType > > aCTSeq( xCTCnt->getChartTypes()); |
| if( aCTSeq.getLength()) |
| { |
| aCTSeq[0] = xCT; |
| xCTCnt->setChartTypes( aCTSeq ); |
| } |
| else |
| xCTCnt->addChartType( xCT ); |
| |
| Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW ); |
| xDSCnt->setDataSeries( aSeriesSeq[nSeriesIdx] ); |
| } |
| else |
| { |
| // reuse existing chart type |
| OSL_ASSERT( xCT.is()); |
| Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW ); |
| Sequence< Reference< XDataSeries > > aNewSeriesSeq( xDSCnt->getDataSeries()); |
| sal_Int32 nNewStartIndex = aNewSeriesSeq.getLength(); |
| aNewSeriesSeq.realloc( nNewStartIndex + aSeriesSeq[nSeriesIdx].getLength() ); |
| ::std::copy( aSeriesSeq[nSeriesIdx].getConstArray(), |
| aSeriesSeq[nSeriesIdx].getConstArray() + aSeriesSeq[nSeriesIdx].getLength(), |
| aNewSeriesSeq.getArray() + nNewStartIndex ); |
| xDSCnt->setDataSeries( aNewSeriesSeq ); |
| } |
| |
| // spread the series over the available coordinate systems |
| if( rCoordSys.getLength() > (nCooSysIdx + 1) ) |
| ++nCooSysIdx; |
| } |
| } |
| } |
| catch( uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| } |
| |
| void ChartTypeTemplate::copyPropertiesFromOldToNewCoordianteSystem( |
| const Sequence< Reference< XChartType > > & rOldChartTypesSeq, |
| const Reference< XChartType > & xNewChartType ) |
| { |
| Reference< beans::XPropertySet > xDestination( xNewChartType, uno::UNO_QUERY ); |
| if( !xDestination.is() ) |
| return; |
| |
| OUString aNewChartType( xNewChartType->getChartType() ); |
| |
| Reference< beans::XPropertySet > xSource; |
| sal_Int32 nN=0; |
| for( nN=0; nN<rOldChartTypesSeq.getLength();++nN) |
| { |
| Reference< XChartType > xOldType( rOldChartTypesSeq[nN] ); |
| if( xOldType.is() && xOldType->getChartType().equals( aNewChartType ) ) |
| { |
| xSource.set( Reference< beans::XPropertySet >(xOldType, uno::UNO_QUERY ) ); |
| if( xSource.is() ) |
| break; |
| } |
| } |
| if( xSource.is() ) |
| comphelper::copyProperties( xSource, xDestination ); |
| } |
| |
| // ________ |
| |
| Sequence< OUString > ChartTypeTemplate::getSupportedServiceNames_Static() |
| { |
| Sequence< OUString > aServices( 3 ); |
| aServices[ 0 ] = C2U( "com.sun.star.chart2.ChartTypeTemplate" ); |
| aServices[ 1 ] = C2U( "com.sun.star.layout.LayoutElement" ); |
| aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" ); |
| return aServices; |
| } |
| |
| Reference< uno::XComponentContext > ChartTypeTemplate::GetComponentContext() const |
| { |
| return m_xContext; |
| } |
| |
| // ================================================================================ |
| |
| // implement XServiceInfo methods basing upon getSupportedServiceNames_Static |
| APPHELPER_XSERVICEINFO_IMPL( ChartTypeTemplate, |
| C2U( "com.sun.star.comp.chart.ChartTypeTemplate" )); |
| } // namespace chart |