diff options
Diffstat (limited to 'oox/source/drawingml/chart')
28 files changed, 7558 insertions, 0 deletions
diff --git a/oox/source/drawingml/chart/axiscontext.cxx b/oox/source/drawingml/chart/axiscontext.cxx new file mode 100644 index 000000000000..1066f91c0e19 --- /dev/null +++ b/oox/source/drawingml/chart/axiscontext.cxx @@ -0,0 +1,318 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/axiscontext.hxx" +#include "oox/drawingml/shapepropertiescontext.hxx" +#include "oox/drawingml/textbodycontext.hxx" +#include "oox/drawingml/chart/axismodel.hxx" +#include "oox/drawingml/chart/titlecontext.hxx" + +using ::rtl::OUString; +using ::oox::core::ContextHandlerRef; +using ::oox::core::ContextHandler2Helper; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +AxisDispUnitsContext::AxisDispUnitsContext( ContextHandler2Helper& rParent, AxisDispUnitsModel& rModel ) : + ContextBase< AxisDispUnitsModel >( rParent, rModel ) +{ +} + +AxisDispUnitsContext::~AxisDispUnitsContext() +{ +} + +ContextHandlerRef AxisDispUnitsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( dispUnits ): + switch( nElement ) + { + case C_TOKEN( builtInUnit ): + mrModel.mnBuiltInUnit = rAttribs.getToken( XML_val, XML_thousands ); + return 0; + case C_TOKEN( custUnit ): + mrModel.mfCustomUnit = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( dispUnitsLbl ): + return this; + } + break; + + case C_TOKEN( dispUnitsLbl ): + switch( nElement ) + { + case C_TOKEN( layout ): + return new LayoutContext( *this, mrModel.mxLayout.create() ); + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( tx ): + return new TextContext( *this, mrModel.mxText.create() ); + case C_TOKEN( txPr ): + return new TextBodyContext( *this, mrModel.mxTextProp.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +AxisContextBase::AxisContextBase( ContextHandler2Helper& rParent, AxisModel& rModel ) : + ContextBase< AxisModel >( rParent, rModel ) +{ +} + +AxisContextBase::~AxisContextBase() +{ +} + +ContextHandlerRef AxisContextBase::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( catAx ): + case C_TOKEN( dateAx ): + case C_TOKEN( serAx ): + case C_TOKEN( valAx ): + switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.mnAxisId = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( crossAx ): + mrModel.mnCrossAxisId = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( crosses ): + mrModel.mnCrossMode = rAttribs.getToken( XML_val, XML_autoZero ); + return 0; + case C_TOKEN( crossesAt ): + mrModel.mofCrossesAt = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( delete ): + // default is 'false', not 'true' as specified + mrModel.mbDeleted = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( majorGridlines ): + return new ShapePrWrapperContext( *this, mrModel.mxMajorGridLines.create() ); + case C_TOKEN( majorTickMark ): + // default is 'out', not 'cross' as specified + mrModel.mnMajorTickMark = rAttribs.getToken( XML_val, XML_out ); + return 0; + case C_TOKEN( minorGridlines ): + return new ShapePrWrapperContext( *this, mrModel.mxMinorGridLines.create() ); + case C_TOKEN( minorTickMark ): + // default is 'none', not 'cross' as specified + mrModel.mnMinorTickMark = rAttribs.getToken( XML_val, XML_none ); + return 0; + case C_TOKEN( numFmt ): + mrModel.maNumberFormat.setAttributes( rAttribs ); + return 0; + case C_TOKEN( scaling ): + return this; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( tickLblPos ): + mrModel.mnTickLabelPos = rAttribs.getToken( XML_val, XML_nextTo ); + return 0; + case C_TOKEN( title ): + return new TitleContext( *this, mrModel.mxTitle.create() ); + case C_TOKEN( txPr ): + return new TextBodyContext( *this, mrModel.mxTextProp.create() ); + } + break; + + case C_TOKEN( scaling ): + switch( nElement ) + { + case C_TOKEN( logBase ): + mrModel.mofLogBase = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( max ): + mrModel.mofMax = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( min ): + mrModel.mofMin = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( orientation ): + mrModel.mnOrientation = rAttribs.getToken( XML_val, XML_minMax ); + return 0; + } + break; + } + return 0; +} + +// ============================================================================ + +CatAxisContext::CatAxisContext( ContextHandler2Helper& rParent, AxisModel& rModel ) : + AxisContextBase( rParent, rModel ) +{ +} + +CatAxisContext::~CatAxisContext() +{ +} + +ContextHandlerRef CatAxisContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( auto ): + // default is 'false', not 'true' as specified + mrModel.mbAuto = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( axPos ): + mrModel.mnAxisPos = rAttribs.getToken( XML_val, XML_TOKEN_INVALID ); + return 0; + case C_TOKEN( lblAlgn ): + mrModel.mnLabelAlign = rAttribs.getToken( XML_val, XML_ctr ); + return 0; + case C_TOKEN( lblOffset ): + mrModel.mnLabelOffset = rAttribs.getInteger( XML_val, 100 ); + return 0; + case C_TOKEN( noMultiLvlLbl ): + // default is 'false', not 'true' as specified + mrModel.mbNoMultiLevel = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( tickLblSkip ): + mrModel.mnTickLabelSkip = rAttribs.getInteger( XML_val, 0 ); + return 0; + case C_TOKEN( tickMarkSkip ): + mrModel.mnTickMarkSkip = rAttribs.getInteger( XML_val, 0 ); + return 0; + } + return AxisContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +DateAxisContext::DateAxisContext( ContextHandler2Helper& rParent, AxisModel& rModel ) : + AxisContextBase( rParent, rModel ) +{ +} + +DateAxisContext::~DateAxisContext() +{ +} + +ContextHandlerRef DateAxisContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( auto ): + // default is 'false', not 'true' as specified + mrModel.mbAuto = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( baseTimeUnit ): + mrModel.mnBaseTimeUnit = rAttribs.getToken( XML_val, XML_days ); + return 0; + case C_TOKEN( lblOffset ): + mrModel.mnLabelOffset = rAttribs.getInteger( XML_val, 100 ); + return 0; + case C_TOKEN( majorTimeUnit ): + mrModel.mnMajorTimeUnit = rAttribs.getToken( XML_val, XML_days ); + return 0; + case C_TOKEN( majorUnit ): + mrModel.mofMajorUnit = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( minorTimeUnit ): + mrModel.mnMinorTimeUnit = rAttribs.getToken( XML_val, XML_days ); + return 0; + case C_TOKEN( minorUnit ): + mrModel.mofMinorUnit = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + } + return AxisContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +SerAxisContext::SerAxisContext( ContextHandler2Helper& rParent, AxisModel& rModel ) : + AxisContextBase( rParent, rModel ) +{ +} + +SerAxisContext::~SerAxisContext() +{ +} + +ContextHandlerRef SerAxisContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( tickLblSkip ): + mrModel.mnTickLabelSkip = rAttribs.getInteger( XML_val, 0 ); + return 0; + case C_TOKEN( tickMarkSkip ): + mrModel.mnTickMarkSkip = rAttribs.getInteger( XML_val, 0 ); + return 0; + } + return AxisContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +ValAxisContext::ValAxisContext( ContextHandler2Helper& rParent, AxisModel& rModel ) : + AxisContextBase( rParent, rModel ) +{ +} + +ValAxisContext::~ValAxisContext() +{ +} + +ContextHandlerRef ValAxisContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( crossBetween ): + mrModel.mnCrossBetween = rAttribs.getToken( XML_val, XML_between ); + return 0; + case C_TOKEN( dispUnits ): + return new AxisDispUnitsContext( *this, mrModel.mxDispUnits.create() ); + case C_TOKEN( majorUnit ): + mrModel.mofMajorUnit = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( minorUnit ): + mrModel.mofMinorUnit = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + } + return AxisContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/axisconverter.cxx b/oox/source/drawingml/chart/axisconverter.cxx new file mode 100644 index 000000000000..da4fc3e5b83f --- /dev/null +++ b/oox/source/drawingml/chart/axisconverter.cxx @@ -0,0 +1,333 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/axisconverter.hxx" +#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp> +#include <com/sun/star/chart/ChartAxisLabelPosition.hpp> +#include <com/sun/star/chart/ChartAxisMarkPosition.hpp> +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart2/TickmarkStyle.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/XAxis.hpp> +#include <com/sun/star/chart2/XCoordinateSystem.hpp> +#include <com/sun/star/chart2/XTitled.hpp> +#include "oox/drawingml/lineproperties.hxx" +#include "oox/drawingml/chart/axismodel.hxx" +#include "oox/drawingml/chart/titleconverter.hxx" +#include "oox/drawingml/chart/typegroupconverter.hxx" +#include "properties.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::chart2::IncrementData; +using ::com::sun::star::chart2::ScaleData; +using ::com::sun::star::chart2::SubIncrement; +using ::com::sun::star::chart2::XAxis; +using ::com::sun::star::chart2::XCoordinateSystem; +using ::com::sun::star::chart2::XScaling; +using ::com::sun::star::chart2::XTitled; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +template< typename Type > +inline void lclSetValueOrClearAny( Any& orAny, const OptValue< Type >& roValue ) +{ + if( roValue.has() ) orAny <<= roValue.get(); else orAny.clear(); +} + +void lclSetScaledValueOrClearAny( Any& orAny, const OptValue< double >& rofValue, const Reference< XScaling >& rxScaling ) +{ + if( rofValue.has() && rxScaling.is() ) + orAny <<= rxScaling->doScaling( rofValue.get() ); + else + lclSetValueOrClearAny( orAny, rofValue ); +} + +bool lclIsLogarithmicScale( const AxisModel& rAxisModel ) +{ + return rAxisModel.mofLogBase.has() && (2.0 <= rAxisModel.mofLogBase.get()) && (rAxisModel.mofLogBase.get() <= 1000.0); +} + +::com::sun::star::chart::ChartAxisLabelPosition lclGetLabelPosition( sal_Int32 nToken ) +{ + using namespace ::com::sun::star::chart; + switch( nToken ) + { + case XML_high: return ChartAxisLabelPosition_OUTSIDE_END; + case XML_low: return ChartAxisLabelPosition_OUTSIDE_START; + case XML_nextTo: return ChartAxisLabelPosition_NEAR_AXIS; + } + return ChartAxisLabelPosition_NEAR_AXIS; +} + +sal_Int32 lclGetTickMark( sal_Int32 nToken ) +{ + using namespace ::com::sun::star::chart2::TickmarkStyle; + switch( nToken ) + { + case XML_in: return INNER; + case XML_out: return OUTER; + case XML_cross: return INNER | OUTER; + } + return NONE; +} + +} // namespace + +// ============================================================================ + +AxisConverter::AxisConverter( const ConverterRoot& rParent, AxisModel& rModel ) : + ConverterBase< AxisModel >( rParent, rModel ) +{ +} + +AxisConverter::~AxisConverter() +{ +} + +void AxisConverter::convertFromModel( const Reference< XCoordinateSystem >& rxCoordSystem, + TypeGroupConverter& rTypeGroup, const AxisModel* pCrossingAxis, sal_Int32 nAxesSetIdx, sal_Int32 nAxisIdx ) +{ + Reference< XAxis > xAxis; + try + { + namespace cssc = ::com::sun::star::chart; + namespace cssc2 = ::com::sun::star::chart2; + + const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo(); + ObjectFormatter& rFormatter = getFormatter(); + + // create the axis object (always) + xAxis.set( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.Axis" ) ), UNO_QUERY_THROW ); + PropertySet aAxisProp( xAxis ); + // #i58688# axis enabled + aAxisProp.setProperty( PROP_Show, !mrModel.mbDeleted ); + + // axis line, tick, and gridline properties --------------------------- + + // show axis labels + aAxisProp.setProperty( PROP_DisplayLabels, mrModel.mnTickLabelPos != XML_none ); + aAxisProp.setProperty( PROP_LabelPosition, lclGetLabelPosition( mrModel.mnTickLabelPos ) ); + // no X axis line in radar charts + if( (nAxisIdx == API_X_AXIS) && (rTypeInfo.meTypeCategory == TYPECATEGORY_RADAR) ) + mrModel.mxShapeProp.getOrCreate().getLineProperties().maLineFill.moFillType = XML_noFill; + // axis line and tick label formatting + rFormatter.convertFormatting( aAxisProp, mrModel.mxShapeProp, mrModel.mxTextProp, OBJECTTYPE_AXIS ); + // tick label rotation + rFormatter.convertTextRotation( aAxisProp, mrModel.mxTextProp, true ); + + // tick mark style + aAxisProp.setProperty( PROP_MajorTickmarks, lclGetTickMark( mrModel.mnMajorTickMark ) ); + aAxisProp.setProperty( PROP_MinorTickmarks, lclGetTickMark( mrModel.mnMinorTickMark ) ); + aAxisProp.setProperty( PROP_MarkPosition, cssc::ChartAxisMarkPosition_AT_AXIS ); + + // main grid + PropertySet aGridProp( xAxis->getGridProperties() ); + aGridProp.setProperty( PROP_Show, mrModel.mxMajorGridLines.is() ); + if( mrModel.mxMajorGridLines.is() ) + rFormatter.convertFrameFormatting( aGridProp, mrModel.mxMajorGridLines, OBJECTTYPE_MAJORGRIDLINE ); + + // sub grid + Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties(); + if( aSubGridPropSeq.hasElements() ) + { + PropertySet aSubGridProp( aSubGridPropSeq[ 0 ] ); + aSubGridProp.setProperty( PROP_Show, mrModel.mxMinorGridLines.is() ); + if( mrModel.mxMinorGridLines.is() ) + rFormatter.convertFrameFormatting( aSubGridProp, mrModel.mxMinorGridLines, OBJECTTYPE_MINORGRIDLINE ); + } + + // axis type and X axis categories ------------------------------------ + + ScaleData aScaleData = xAxis->getScaleData(); + // set axis type + switch( nAxisIdx ) + { + case API_X_AXIS: + if( rTypeInfo.mbCategoryAxis ) + { + OSL_ENSURE( (mrModel.mnTypeId == C_TOKEN( catAx )) || (mrModel.mnTypeId == C_TOKEN( dateAx )), + "AxisConverter::convertFromModel - unexpected axis model type (must: c:catAx or c:dateEx)" ); + aScaleData.AxisType = cssc2::AxisType::CATEGORY; + aScaleData.Categories = rTypeGroup.createCategorySequence(); + } + else + { + OSL_ENSURE( mrModel.mnTypeId == C_TOKEN( valAx ), "AxisConverter::convertFromModel - unexpected axis model type (must: c:valAx)" ); + aScaleData.AxisType = cssc2::AxisType::REALNUMBER; + } + break; + case API_Y_AXIS: + OSL_ENSURE( mrModel.mnTypeId == C_TOKEN( valAx ), "AxisConverter::convertFromModel - unexpected axis model type (must: c:valAx)" ); + aScaleData.AxisType = rTypeGroup.isPercent() ? cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER; + break; + case API_Z_AXIS: + OSL_ENSURE( mrModel.mnTypeId == C_TOKEN( serAx ), "AxisConverter::convertFromModel - unexpected axis model type (must: c:serAx)" ); + OSL_ENSURE( rTypeGroup.isDeep3dChart(), "AxisConverter::convertFromModel - series axis not supported by this chart type" ); + aScaleData.AxisType = cssc2::AxisType::SERIES; + break; + } + + // axis scaling and increment ----------------------------------------- + + switch( aScaleData.AxisType ) + { + case cssc2::AxisType::CATEGORY: + case cssc2::AxisType::SERIES: + { + // do not overlap text unless all labels are visible + aAxisProp.setProperty( PROP_TextOverlap, mrModel.mnTickLabelSkip == 1 ); + // do not break text into several lines + aAxisProp.setProperty( PROP_TextBreak, false ); + // do not stagger labels in two lines + aAxisProp.setProperty( PROP_ArrangeOrder, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE ); + //! TODO #i58731# show n-th category + } + break; + case cssc2::AxisType::REALNUMBER: + case cssc2::AxisType::PERCENT: + { + // scaling algorithm + bool bLogScale = lclIsLogarithmicScale( mrModel ); + OUString aScalingService = bLogScale ? + CREATE_OUSTRING( "com.sun.star.chart2.LogarithmicScaling" ) : + CREATE_OUSTRING( "com.sun.star.chart2.LinearScaling" ); + aScaleData.Scaling.set( createInstance( aScalingService ), UNO_QUERY ); + // min/max + lclSetValueOrClearAny( aScaleData.Minimum, mrModel.mofMin ); + lclSetValueOrClearAny( aScaleData.Maximum, mrModel.mofMax ); + // major increment + IncrementData& rIncrementData = aScaleData.IncrementData; + lclSetScaledValueOrClearAny( rIncrementData.Distance, mrModel.mofMajorUnit, aScaleData.Scaling ); + // minor increment + Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements; + rSubIncrementSeq.realloc( 1 ); + Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount; + if( bLogScale ) + { + if( mrModel.mofMinorUnit.has() ) + rIntervalCount <<= sal_Int32( 9 ); + } + else + { + OptValue< sal_Int32 > onCount; + if( mrModel.mofMajorUnit.has() && mrModel.mofMinorUnit.has() && (0.0 < mrModel.mofMinorUnit.get()) && (mrModel.mofMinorUnit.get() <= mrModel.mofMajorUnit.get()) ) + { + double fCount = mrModel.mofMajorUnit.get() / mrModel.mofMinorUnit.get() + 0.5; + if( (1.0 <= fCount) && (fCount < 1001.0) ) + onCount = static_cast< sal_Int32 >( fCount ); + } + lclSetValueOrClearAny( rIntervalCount, onCount ); + } + } + break; + default: + OSL_ENSURE( false, "AxisConverter::convertFromModel - unknown axis type" ); + } + + /* Do not set a value to the Origin member anymore (already done via + new axis properties 'CrossoverPosition' and 'CrossoverValue'). */ + aScaleData.Origin.clear(); + + // axis orientation --------------------------------------------------- + + // #i85167# pie/donut charts need opposite direction at Y axis + // #i87747# radar charts need opposite direction at X axis + bool bMirrorDirection = + ((nAxisIdx == API_Y_AXIS) && (rTypeInfo.meTypeCategory == TYPECATEGORY_PIE)) || + ((nAxisIdx == API_X_AXIS) && (rTypeInfo.meTypeCategory == TYPECATEGORY_RADAR)); + bool bReverse = (mrModel.mnOrientation == XML_maxMin) != bMirrorDirection; + aScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL; + + // write back scaling data + xAxis->setScaleData( aScaleData ); + + // number format ------------------------------------------------------ + + if( (aScaleData.AxisType == cssc2::AxisType::REALNUMBER) || (aScaleData.AxisType == cssc2::AxisType::PERCENT) ) + getFormatter().convertNumberFormat( aAxisProp, mrModel.maNumberFormat ); + + // position of crossing axis ------------------------------------------ + + bool bManualCrossing = mrModel.mofCrossesAt.has(); + cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE; + if( !bManualCrossing ) switch( mrModel.mnCrossMode ) + { + case XML_min: eAxisPos = cssc::ChartAxisPosition_START; break; + case XML_max: eAxisPos = cssc::ChartAxisPosition_END; break; + case XML_autoZero: eAxisPos = cssc::ChartAxisPosition_VALUE; break; + } + aAxisProp.setProperty( PROP_CrossoverPosition, eAxisPos ); + + // calculate automatic origin depending on scaling mode of crossing axis + bool bCrossingLogScale = pCrossingAxis && lclIsLogarithmicScale( *pCrossingAxis ); + double fCrossingPos = bManualCrossing ? mrModel.mofCrossesAt.get() : (bCrossingLogScale ? 1.0 : 0.0); + aAxisProp.setProperty( PROP_CrossoverValue, fCrossingPos ); + + // axis title --------------------------------------------------------- + + // in radar charts, title objects may exist, but are not shown + if( mrModel.mxTitle.is() && (rTypeGroup.getTypeInfo().meTypeCategory != TYPECATEGORY_RADAR) ) + { + Reference< XTitled > xTitled( xAxis, UNO_QUERY_THROW ); + TitleConverter aTitleConv( *this, *mrModel.mxTitle ); + aTitleConv.convertFromModel( xTitled, CREATE_OUSTRING( "Axis Title" ), OBJECTTYPE_AXISTITLE, nAxesSetIdx, nAxisIdx ); + } + } + catch( Exception& ) + { + } + + if( xAxis.is() && rxCoordSystem.is() ) try + { + // insert axis into coordinate system + rxCoordSystem->setAxisByDimension( nAxisIdx, xAxis, nAxesSetIdx ); + } + catch( Exception& ) + { + OSL_ENSURE( false, "AxisConverter::convertFromModel - cannot insert axis into coordinate system" ); + } +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/axismodel.cxx b/oox/source/drawingml/chart/axismodel.cxx new file mode 100644 index 000000000000..9f1d52adc0d2 --- /dev/null +++ b/oox/source/drawingml/chart/axismodel.cxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/axismodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +AxisDispUnitsModel::AxisDispUnitsModel() : + mfCustomUnit( 0.0 ), + mnBuiltInUnit( XML_TOKEN_INVALID ) +{ +} + +AxisDispUnitsModel::~AxisDispUnitsModel() +{ +} + +// ============================================================================ + +AxisModel::AxisModel( sal_Int32 nTypeId ) : + mnAxisId( -1 ), + mnAxisPos( XML_TOKEN_INVALID ), + mnBaseTimeUnit( XML_days ), + mnCrossAxisId( -1 ), + mnCrossBetween( XML_between ), + mnCrossMode( XML_autoZero ), + mnLabelAlign( XML_ctr ), + mnLabelOffset( 100 ), + mnMajorTickMark( XML_out ), + mnMajorTimeUnit( XML_days ), + mnMinorTickMark( XML_none ), + mnMinorTimeUnit( XML_days ), + mnOrientation( XML_minMax ), + mnTickLabelPos( XML_nextTo ), + mnTickLabelSkip( 0 ), + mnTickMarkSkip( 0 ), + mnTypeId( nTypeId ), + mbAuto( false ), + mbDeleted( false ), + mbNoMultiLevel( false ) +{ +} + +AxisModel::~AxisModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/chartcontextbase.cxx b/oox/source/drawingml/chart/chartcontextbase.cxx new file mode 100644 index 000000000000..d3746f07ba6c --- /dev/null +++ b/oox/source/drawingml/chart/chartcontextbase.cxx @@ -0,0 +1,120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/chartcontextbase.hxx" +#include "oox/drawingml/shapepropertiescontext.hxx" +#include "oox/drawingml/chart/modelbase.hxx" + +using ::oox::core::ContextHandler2Helper; +using ::oox::core::ContextHandlerRef; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +ShapePrWrapperContext::ShapePrWrapperContext( ContextHandler2Helper& rParent, Shape& rModel ) : + ContextBase< Shape >( rParent, rModel ) +{ +} + +ShapePrWrapperContext::~ShapePrWrapperContext() +{ +} + +ContextHandlerRef ShapePrWrapperContext::onCreateContext( sal_Int32 nElement, const AttributeList& ) +{ + return (isRootElement() && (nElement == C_TOKEN( spPr ))) ? new ShapePropertiesContext( *this, mrModel ) : 0; +} + +// ============================================================================ + +LayoutContext::LayoutContext( ContextHandler2Helper& rParent, LayoutModel& rModel ) : + ContextBase< LayoutModel >( rParent, rModel ) +{ +} + +LayoutContext::~LayoutContext() +{ +} + +ContextHandlerRef LayoutContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( layout ): + switch( nElement ) + { + case C_TOKEN( manualLayout ): + mrModel.mbAutoLayout = false; + return this; + } + break; + + case C_TOKEN( manualLayout ): + switch( nElement ) + { + case C_TOKEN( x ): + mrModel.mfX = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( y ): + mrModel.mfY = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( w ): + mrModel.mfW = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( h ): + mrModel.mfH = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( xMode ): + mrModel.mnXMode = rAttribs.getToken( XML_val, XML_factor ); + return 0; + case C_TOKEN( yMode ): + mrModel.mnYMode = rAttribs.getToken( XML_val, XML_factor ); + return 0; + case C_TOKEN( wMode ): + mrModel.mnWMode = rAttribs.getToken( XML_val, XML_factor ); + return 0; + case C_TOKEN( hMode ): + mrModel.mnHMode = rAttribs.getToken( XML_val, XML_factor ); + return 0; + case C_TOKEN( layoutTarget ): + mrModel.mnTarget = rAttribs.getToken( XML_val, XML_outer ); + return 0; + } + break; + } + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/chartconverter.cxx b/oox/source/drawingml/chart/chartconverter.cxx new file mode 100644 index 000000000000..efd8e6d021e1 --- /dev/null +++ b/oox/source/drawingml/chart/chartconverter.cxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/chartconverter.hxx" +#include <com/sun/star/chart2/XChartDocument.hpp> +#include "oox/drawingml/chart/chartspaceconverter.hxx" +#include "oox/drawingml/chart/chartspacemodel.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::awt::Point; +using ::com::sun::star::awt::Size; +using ::com::sun::star::drawing::XShapes; +using ::com::sun::star::chart2::XChartDocument; +using ::com::sun::star::chart2::data::XDataProvider; +using ::com::sun::star::chart2::data::XDataSequence; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +ChartConverter::ChartConverter() +{ +} + +ChartConverter::~ChartConverter() +{ +} + +void ChartConverter::convertFromModel( XmlFilterBase& rFilter, + ChartSpaceModel& rChartModel, const Reference< XChartDocument >& rxChartDoc, + const Reference< XShapes >& rxExternalPage, const Point& rChartPos, const Size& rChartSize ) +{ + OSL_ENSURE( rxChartDoc.is(), "ChartConverter::convertFromModel - missing chart document" ); + if( rxChartDoc.is() ) + { + ConverterRoot aConvBase( rFilter, *this, rChartModel, rxChartDoc, rChartSize ); + ChartSpaceConverter aSpaceConv( aConvBase, rChartModel ); + aSpaceConv.convertFromModel( rxExternalPage, rChartPos ); + } +} + +void ChartConverter::createDataProvider( const Reference< XChartDocument >& rxChartDoc ) +{ + try + { + if( !rxChartDoc->hasInternalDataProvider() ) + rxChartDoc->createInternalDataProvider( sal_False ); + } + catch( Exception& ) + { + } +} + +Reference< XDataSequence > ChartConverter::createDataSequence( const Reference< XDataProvider >&, const DataSequenceModel& ) +{ + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/chartdrawingfragment.cxx b/oox/source/drawingml/chart/chartdrawingfragment.cxx new file mode 100644 index 000000000000..fcc350b583c3 --- /dev/null +++ b/oox/source/drawingml/chart/chartdrawingfragment.cxx @@ -0,0 +1,235 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/chartdrawingfragment.hxx" +#include "oox/core/xmlfilterbase.hxx" +#include "oox/drawingml/connectorshapecontext.hxx" +#include "oox/drawingml/graphicshapecontext.hxx" +#include "oox/drawingml/shapecontext.hxx" +#include "oox/drawingml/shapegroupcontext.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::awt::Point; +using ::com::sun::star::awt::Rectangle; +using ::com::sun::star::awt::Size; +using ::com::sun::star::drawing::XShapes; +using ::oox::core::ContextHandlerRef; +using ::oox::core::FragmentHandler2; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +ShapeAnchor::ShapeAnchor( bool bRelSize ) : + mbRelSize( bRelSize ) +{ +} + +void ShapeAnchor::importExt( const AttributeList& rAttribs ) +{ + OSL_ENSURE( !mbRelSize, "ShapeAnchor::importExt - unexpected 'cdr:ext' element" ); + maSize.Width = rAttribs.getHyper( XML_cx, 0 ); + maSize.Height = rAttribs.getHyper( XML_cy, 0 ); +} + +void ShapeAnchor::setPos( sal_Int32 nElement, sal_Int32 nParentContext, const OUString& rValue ) +{ + AnchorPosModel* pAnchorPos = 0; + switch( nParentContext ) + { + case CDR_TOKEN( from ): + pAnchorPos = &maFrom; + break; + case CDR_TOKEN( to ): + OSL_ENSURE( mbRelSize, "ShapeAnchor::setPos - unexpected 'cdr:to' element" ); + pAnchorPos = &maTo; + break; + default: + OSL_ENSURE( false, "ShapeAnchor::setPos - unexpected parent element" ); + } + if( pAnchorPos ) switch( nElement ) + { + case CDR_TOKEN( x ): pAnchorPos->mfX = rValue.toDouble(); break; + case CDR_TOKEN( y ): pAnchorPos->mfY = rValue.toDouble(); break; + default: OSL_ENSURE( false, "ShapeAnchor::setPos - unexpected element" ); + } +} + +Rectangle ShapeAnchor::calcEmuLocation( const EmuRectangle& rEmuChartRect ) const +{ + Rectangle aLoc( -1, -1, -1, -1 ); + + OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::calcEmuLocation - invalid from position" ); + OSL_ENSURE( mbRelSize ? maTo.isValid() : maSize.isValid(), "ShapeAnchor::calcEmuLocation - invalid to/size" ); + if( maFrom.isValid() && (mbRelSize ? maTo.isValid() : maSize.isValid()) ) + { + // calculate shape position + aLoc.X = getLimitedValue< sal_Int32, double >( maFrom.mfX * rEmuChartRect.Width, 0, SAL_MAX_INT32 ); + aLoc.Y = getLimitedValue< sal_Int32, double >( maFrom.mfY * rEmuChartRect.Height, 0, SAL_MAX_INT32 ); + + // calculate shape size + if( mbRelSize ) + { + aLoc.Width = getLimitedValue< sal_Int32, double >( maTo.mfX * rEmuChartRect.Width, 0, SAL_MAX_INT32 ) - aLoc.X; + if( aLoc.Width < 0 ) + { + aLoc.X += aLoc.Width; + aLoc.Width *= -1; + } + aLoc.Height = getLimitedValue< sal_Int32, double >( maTo.mfY * rEmuChartRect.Height, 0, SAL_MAX_INT32 ) - aLoc.Y; + if( aLoc.Height < 0 ) + { + aLoc.Y += aLoc.Height; + aLoc.Height *= -1; + } + } + else + { + aLoc.Width = getLimitedValue< sal_Int32, sal_Int64 >( maSize.Width, 0, SAL_MAX_INT32 ); + aLoc.Height = getLimitedValue< sal_Int32, sal_Int64 >( maSize.Height, 0, SAL_MAX_INT32 ); + } + } + + return aLoc; +} +// ============================================================================ + +ChartDrawingFragment::ChartDrawingFragment( XmlFilterBase& rFilter, + const OUString& rFragmentPath, const Reference< XShapes >& rxDrawPage, + const Size& rChartSize, const Point& rShapesOffset, bool bOleSupport ) : + FragmentHandler2( rFilter, rFragmentPath ), + mxDrawPage( rxDrawPage ), + mbOleSupport( bOleSupport ) +{ + maEmuChartRect.X = static_cast< sal_Int64 >( rShapesOffset.X ) * 360; + maEmuChartRect.Y = static_cast< sal_Int64 >( rShapesOffset.Y ) * 360; + maEmuChartRect.Width = static_cast< sal_Int64 >( rChartSize.Width ) * 360; + maEmuChartRect.Height = static_cast< sal_Int64 >( rChartSize.Height ) * 360; +} + +ChartDrawingFragment::~ChartDrawingFragment() +{ +} + +ContextHandlerRef ChartDrawingFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case XML_ROOT_CONTEXT: + if( nElement == C_TOKEN( userShapes ) ) return this; + break; + + case C_TOKEN( userShapes ): + switch( nElement ) + { + case CDR_TOKEN( absSizeAnchor ): + mxAnchor.reset( new ShapeAnchor( false ) ); + return this; + case CDR_TOKEN( relSizeAnchor ): + mxAnchor.reset( new ShapeAnchor( true ) ); + return this; + } + break; + + case CDR_TOKEN( absSizeAnchor ): + case CDR_TOKEN( relSizeAnchor ): + switch( nElement ) + { + case CDR_TOKEN( sp ): + mxShape.reset( new Shape( "com.sun.star.drawing.CustomShape" ) ); + return new ShapeContext( *this, ShapePtr(), mxShape ); + case CDR_TOKEN( cxnSp ): + mxShape.reset( new Shape( "com.sun.star.drawing.ConnectorShape" ) ); + return new ConnectorShapeContext( *this, ShapePtr(), mxShape ); + case CDR_TOKEN( pic ): + mxShape.reset( new Shape( "com.sun.star.drawing.GraphicObjectShape" ) ); + return new GraphicShapeContext( *this, ShapePtr(), mxShape ); + case CDR_TOKEN( graphicFrame ): + if( !mbOleSupport ) + return 0; + mxShape.reset( new Shape( "com.sun.star.drawing.OLE2Shape" ) ); + return new GraphicalObjectFrameContext( *this, ShapePtr(), mxShape, true ); + case CDR_TOKEN( grpSp ): + mxShape.reset( new Shape( "com.sun.star.drawing.GroupShape" ) ); + return new ShapeGroupContext( *this, ShapePtr(), mxShape ); + + case CDR_TOKEN( from ): + case CDR_TOKEN( to ): + return this; + + case CDR_TOKEN( ext ): + if( mxAnchor.get() ) mxAnchor->importExt( rAttribs ); + return 0; + } + break; + + case CDR_TOKEN( from ): + case CDR_TOKEN( to ): + switch( nElement ) + { + case CDR_TOKEN( x ): + case CDR_TOKEN( y ): + return this; // collect value in onEndElement() + } + break; + } + return 0; +} + +void ChartDrawingFragment::onEndElement( const OUString& rChars ) +{ + switch( getCurrentElement() ) + { + case CDR_TOKEN( x ): + case CDR_TOKEN( y ): + if( mxAnchor.get() ) mxAnchor->setPos( getCurrentElement(), getPreviousElement(), rChars ); + break; + + case CDR_TOKEN( absSizeAnchor ): + case CDR_TOKEN( relSizeAnchor ): + if( mxDrawPage.is() && mxShape.get() && mxAnchor.get() ) + { + Rectangle aLoc = mxAnchor->calcEmuLocation( maEmuChartRect ); + if( (aLoc.X >= 0) && (aLoc.Y >= 0) && (aLoc.Width >= 0) && (aLoc.Height >= 0) ) + mxShape->addShape( getFilter(), getFilter().getCurrentTheme(), mxDrawPage, &aLoc ); + } + mxShape.reset(); + mxAnchor.reset(); + break; + } +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/chartspaceconverter.cxx b/oox/source/drawingml/chart/chartspaceconverter.cxx new file mode 100644 index 000000000000..54212f1bdbda --- /dev/null +++ b/oox/source/drawingml/chart/chartspaceconverter.cxx @@ -0,0 +1,209 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/chartspaceconverter.hxx" +#include <com/sun/star/chart/MissingValueTreatment.hpp> +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/XTitled.hpp> +#include <com/sun/star/chart2/data/XDataReceiver.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include "oox/core/xmlfilterbase.hxx" +#include "oox/drawingml/chart/chartconverter.hxx" +#include "oox/drawingml/chart/chartdrawingfragment.hxx" +#include "oox/drawingml/chart/chartspacemodel.hxx" +#include "oox/drawingml/chart/plotareaconverter.hxx" +#include "oox/drawingml/chart/titleconverter.hxx" +#include "properties.hxx" + +using ::rtl::OUString; +using ::com::sun::star::awt::Point; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::util::XNumberFormatsSupplier; +using ::com::sun::star::drawing::XDrawPageSupplier; +using ::com::sun::star::drawing::XShapes; +using ::com::sun::star::chart2::XDiagram; +using ::com::sun::star::chart2::XTitled; +using ::com::sun::star::chart2::data::XDataReceiver; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +ChartSpaceConverter::ChartSpaceConverter( const ConverterRoot& rParent, ChartSpaceModel& rModel ) : + ConverterBase< ChartSpaceModel >( rParent, rModel ) +{ +} + +ChartSpaceConverter::~ChartSpaceConverter() +{ +} + +void ChartSpaceConverter::convertFromModel( const Reference< XShapes >& rxExternalPage, const Point& rChartPos ) +{ + /* create data provider (virtual function in the ChartConverter class, + derived converters may create an external data provider) */ + getChartConverter().createDataProvider( getChartDocument() ); + + // attach number formatter of container document to data receiver + try + { + Reference< XDataReceiver > xDataRec( getChartDocument(), UNO_QUERY_THROW ); + Reference< XNumberFormatsSupplier > xNumFmtSupp( getFilter().getModel(), UNO_QUERY_THROW ); + xDataRec->attachNumberFormatsSupplier( xNumFmtSupp ); + } + catch( Exception& ) + { + } + + // formatting of the chart background + PropertySet aBackPropSet( getChartDocument()->getPageBackground() ); + getFormatter().convertFrameFormatting( aBackPropSet, mrModel.mxShapeProp, OBJECTTYPE_CHARTSPACE ); + + // convert plot area (container of all chart type groups) + PlotAreaConverter aPlotAreaConv( *this, mrModel.mxPlotArea.getOrCreate() ); + aPlotAreaConv.convertFromModel( mrModel.mxView3D.getOrCreate() ); + + // plot area converter has created the diagram object + Reference< XDiagram > xDiagram = getChartDocument()->getFirstDiagram(); + + // convert wall and floor formatting in 3D charts + if( xDiagram.is() && aPlotAreaConv.isWall3dChart() ) + { + WallFloorConverter aFloorConv( *this, mrModel.mxFloor.getOrCreate() ); + aFloorConv.convertFromModel( xDiagram, OBJECTTYPE_FLOOR ); + + WallFloorConverter aWallConv( *this, mrModel.mxBackWall.getOrCreate() ); + aWallConv.convertFromModel( xDiagram, OBJECTTYPE_WALL ); + } + + // chart title + if( !mrModel.mbAutoTitleDel ) try + { + /* If the title model is missing, but the chart shows exactly one + series, the series title is shown as chart title. */ + OUString aAutoTitle = aPlotAreaConv.getAutomaticTitle(); + if( mrModel.mxTitle.is() || (aAutoTitle.getLength() > 0) ) + { + if( aAutoTitle.getLength() == 0 ) + aAutoTitle = CREATE_OUSTRING( "Chart Title" ); + Reference< XTitled > xTitled( getChartDocument(), UNO_QUERY_THROW ); + TitleConverter aTitleConv( *this, mrModel.mxTitle.getOrCreate() ); + aTitleConv.convertFromModel( xTitled, aAutoTitle, OBJECTTYPE_CHARTTITLE ); + } + } + catch( Exception& ) + { + } + + // legend + if( xDiagram.is() && mrModel.mxLegend.is() ) + { + LegendConverter aLegendConv( *this, *mrModel.mxLegend ); + aLegendConv.convertFromModel( xDiagram ); + } + + // treatment of missing values + if( xDiagram.is() ) + { + using namespace ::com::sun::star::chart::MissingValueTreatment; + sal_Int32 nMissingValues = LEAVE_GAP; + switch( mrModel.mnDispBlanksAs ) + { + case XML_gap: nMissingValues = LEAVE_GAP; break; + case XML_zero: nMissingValues = USE_ZERO; break; + case XML_span: nMissingValues = CONTINUE; break; + } + PropertySet aDiaProp( xDiagram ); + aDiaProp.setProperty( PROP_MissingValueTreatment, nMissingValues ); + } + + /* Following all conversions needing the old Chart1 API that involves full + initialization of the chart view. */ + namespace cssc = ::com::sun::star::chart; + Reference< cssc::XChartDocument > xChart1Doc( getChartDocument(), UNO_QUERY ); + if( xChart1Doc.is() ) + { + /* Set the IncludeHiddenCells property via the old API as only this + ensures that the data provider and all created sequences get this + flag correctly. */ + PropertySet aDiaProp( xChart1Doc->getDiagram() ); + aDiaProp.setProperty( PROP_IncludeHiddenCells, !mrModel.mbPlotVisOnly ); + + // plot area position and size + aPlotAreaConv.convertPositionFromModel(); + + // positions of main title and all axis titles + convertTitlePositions(); + } + + // embedded drawing shapes + if( mrModel.maDrawingPath.getLength() > 0 ) try + { + /* Get the internal draw page of the chart document, if no external + drawing page has been passed. */ + Reference< XShapes > xShapes; + Point aShapesOffset( 0, 0 ); + if( rxExternalPage.is() ) + { + xShapes = rxExternalPage; + // offset for embedded shapes to move them inside the chart area + aShapesOffset = rChartPos; + } + else + { + Reference< XDrawPageSupplier > xDrawPageSupp( getChartDocument(), UNO_QUERY_THROW ); + xShapes.set( xDrawPageSupp->getDrawPage(), UNO_QUERY_THROW ); + } + + /* If an external drawing page is passed, all embedded shapes will be + inserted there (used e.g. with 'chart sheets' in spreadsheet + documents). In this case, all types of shapes including OLE objects + are supported. If the shapes are inserted into the internal chart + drawing page instead, it is not possible to embed OLE objects. */ + bool bOleSupport = rxExternalPage.is(); + + // now, xShapes is not null anymore + getFilter().importFragment( new ChartDrawingFragment( + getFilter(), mrModel.maDrawingPath, xShapes, getChartSize(), aShapesOffset, bOleSupport ) ); + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/chartspacefragment.cxx b/oox/source/drawingml/chart/chartspacefragment.cxx new file mode 100644 index 000000000000..75df94e95de7 --- /dev/null +++ b/oox/source/drawingml/chart/chartspacefragment.cxx @@ -0,0 +1,127 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/chartspacefragment.hxx" +#include "oox/drawingml/shapepropertiescontext.hxx" +#include "oox/drawingml/textbodycontext.hxx" +#include "oox/drawingml/chart/chartspacemodel.hxx" +#include "oox/drawingml/chart/plotareacontext.hxx" +#include "oox/drawingml/chart/titlecontext.hxx" + +using ::rtl::OUString; +using ::oox::core::ContextHandlerRef; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +ChartSpaceFragment::ChartSpaceFragment( XmlFilterBase& rFilter, const OUString& rFragmentPath, ChartSpaceModel& rModel ) : + FragmentBase< ChartSpaceModel >( rFilter, rFragmentPath, rModel ) +{ +} + +ChartSpaceFragment::~ChartSpaceFragment() +{ +} + +ContextHandlerRef ChartSpaceFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case XML_ROOT_CONTEXT: + switch( nElement ) + { + case C_TOKEN( chartSpace ): + return this; + } + break; + + case C_TOKEN( chartSpace ): + switch( nElement ) + { + case C_TOKEN( chart ): + return this; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( style ): + mrModel.mnStyle = rAttribs.getInteger( XML_val, 2 ); + return 0; + case C_TOKEN( txPr ): + return new TextBodyContext( *this, mrModel.mxTextProp.create() ); + case C_TOKEN( userShapes ): + mrModel.maDrawingPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ); + return 0; + } + break; + + case C_TOKEN( chart ): + switch( nElement ) + { + case C_TOKEN( autoTitleDeleted ): + // default is 'false', not 'true' as specified + mrModel.mbAutoTitleDel = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( backWall ): + return new WallFloorContext( *this, mrModel.mxBackWall.create() ); + case C_TOKEN( dispBlanksAs ): + mrModel.mnDispBlanksAs = rAttribs.getToken( XML_val, XML_zero ); + return 0; + case C_TOKEN( floor ): + return new WallFloorContext( *this, mrModel.mxFloor.create() ); + case C_TOKEN( legend ): + return new LegendContext( *this, mrModel.mxLegend.create() ); + case C_TOKEN( plotArea ): + return new PlotAreaContext( *this, mrModel.mxPlotArea.create() ); + case C_TOKEN( plotVisOnly ): + // default is 'false', not 'true' as specified + mrModel.mbPlotVisOnly = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( showDLblsOverMax ): + // default is 'false', not 'true' as specified + mrModel.mbShowLabelsOverMax = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( sideWall ): + return new WallFloorContext( *this, mrModel.mxSideWall.create() ); + case C_TOKEN( title ): + return new TitleContext( *this, mrModel.mxTitle.create() ); + case C_TOKEN( view3D ): + return new View3DContext( *this, mrModel.mxView3D.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/chartspacemodel.cxx b/oox/source/drawingml/chart/chartspacemodel.cxx new file mode 100644 index 000000000000..e386334160a8 --- /dev/null +++ b/oox/source/drawingml/chart/chartspacemodel.cxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/chartspacemodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +ChartSpaceModel::ChartSpaceModel() : + mnDispBlanksAs( XML_gap ), // not zero as specified + mnStyle( 2 ), + mbAutoTitleDel( false ), + mbPlotVisOnly( false ), + mbShowLabelsOverMax( false ) +{ +} + +ChartSpaceModel::~ChartSpaceModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/converterbase.cxx b/oox/source/drawingml/chart/converterbase.cxx new file mode 100644 index 000000000000..b5a0511bf1b8 --- /dev/null +++ b/oox/source/drawingml/chart/converterbase.cxx @@ -0,0 +1,422 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/converterbase.hxx" +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/chart/XAxisXSupplier.hpp> +#include <com/sun/star/chart/XAxisYSupplier.hpp> +#include <com/sun/star/chart/XAxisZSupplier.hpp> +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <tools/solar.h> // for F_PI180 +#include "properties.hxx" +#include "oox/core/xmlfilterbase.hxx" +#include "oox/drawingml/theme.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_SET_THROW; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::frame::XModel; +using ::com::sun::star::awt::Point; +using ::com::sun::star::awt::Rectangle; +using ::com::sun::star::awt::Size; +using ::com::sun::star::chart2::RelativePosition; +using ::com::sun::star::chart2::XChartDocument; +using ::com::sun::star::chart2::XTitle; +using ::com::sun::star::drawing::XShape; +using ::oox::core::XmlFilterBase; + +namespace cssc = ::com::sun::star::chart; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +struct TitleKey : public ::std::pair< ObjectType, ::std::pair< sal_Int32, sal_Int32 > > +{ + inline explicit TitleKey( ObjectType eObjType, sal_Int32 nMainIdx = -1, sal_Int32 nSubIdx = -1 ) + { first = eObjType; second.first = nMainIdx; second.second = nSubIdx; } +}; + +// ---------------------------------------------------------------------------- + +/** A helper structure to store all data related to title objects. Needed for + the conversion of manual title positions that needs the old Chart1 API. + */ +struct TitleLayoutInfo +{ + typedef Reference< XShape > (*GetShapeFunc)( const Reference< cssc::XChartDocument >& ); + + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTitle > + mxTitle; /// The API title object. + ModelRef< LayoutModel > mxLayout; /// The layout model, if existing. + GetShapeFunc mpGetShape; /// Helper function to receive the title shape. + + inline explicit TitleLayoutInfo() : mpGetShape( 0 ) {} + + void convertTitlePos( + ConverterRoot& rRoot, + const Reference< cssc::XChartDocument >& rxChart1Doc ); +}; + +void TitleLayoutInfo::convertTitlePos( ConverterRoot& rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc ) +{ + if( mxTitle.is() && mpGetShape ) try + { + // try to get the title shape + Reference< XShape > xTitleShape( mpGetShape( rxChart1Doc ), UNO_SET_THROW ); + // get title rotation angle, needed for correction of position of top-left edge + double fAngle = 0.0; + PropertySet aTitleProp( mxTitle ); + aTitleProp.getProperty( fAngle, PROP_TextRotation ); + // convert the position + LayoutModel& rLayout = mxLayout.getOrCreate(); + LayoutConverter aLayoutConv( rRoot, rLayout ); + aLayoutConv.convertFromModel( xTitleShape, fAngle ); + } + catch( Exception& ) + { + } +} + +// ---------------------------------------------------------------------------- + +/* The following local functions implement getting the XShape interface of all + supported title objects (chart and axes). This needs some effort due to the + design of the old Chart1 API used to access these objects. */ + +/** A code fragment that returns a shape object from the passed shape supplier + using the specified interface function. Checks a boolean property first. */ +#define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \ + PropertySet aPropSet( shape_supplier ); \ + if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \ + return shape_supplier->supplier_func(); \ + return Reference< XShape >(); \ + +/** Implements a function returning the drawing shape of an axis title, if + existing, using the specified API interface and its function. */ +#define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \ +Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \ +{ \ + Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \ + OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \ +} + +/** Returns the drawing shape of the main title, if existing. */ +Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc ) +{ + OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle ) +} + +OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle ) +OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle ) +OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle ) +OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle ) +OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle ) + +#undef OOX_DEFINEFUNC_GETAXISTITLESHAPE +#undef OOX_IMPLEMENT_GETTITLESHAPE + +} // namespace + +// ============================================================================ + +struct ConverterData +{ + typedef ::std::map< TitleKey, TitleLayoutInfo > TitleMap; + + ObjectFormatter maFormatter; + TitleMap maTitles; + XmlFilterBase& mrFilter; + ChartConverter& mrConverter; + Reference< XChartDocument > mxDoc; + Size maSize; + + explicit ConverterData( + XmlFilterBase& rFilter, + ChartConverter& rChartConverter, + const ChartSpaceModel& rChartModel, + const Reference< XChartDocument >& rxChartDoc, + const Size& rChartSize ); + ~ConverterData(); +}; + +// ---------------------------------------------------------------------------- + +ConverterData::ConverterData( + XmlFilterBase& rFilter, + ChartConverter& rChartConverter, + const ChartSpaceModel& rChartModel, + const Reference< XChartDocument >& rxChartDoc, + const Size& rChartSize ) : + maFormatter( rFilter, rxChartDoc, rChartModel ), + mrFilter( rFilter ), + mrConverter( rChartConverter ), + mxDoc( rxChartDoc ), + maSize( rChartSize ) +{ + OSL_ENSURE( mxDoc.is(), "ConverterData::ConverterData - missing chart document" ); + // lock the model to suppress internal updates during conversion + try + { + Reference< XModel > xModel( mxDoc, UNO_QUERY_THROW ); + xModel->lockControllers(); + } + catch( Exception& ) + { + } + + // prepare conversion of title positions + maTitles[ TitleKey( OBJECTTYPE_CHARTTITLE ) ].mpGetShape = lclGetMainTitleShape; + maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetXAxisTitleShape; + maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetYAxisTitleShape; + maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Z_AXIS ) ].mpGetShape = lclGetZAxisTitleShape; + maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetSecXAxisTitleShape; + maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetSecYAxisTitleShape; +} + +ConverterData::~ConverterData() +{ + // unlock the model + try + { + Reference< XModel > xModel( mxDoc, UNO_QUERY_THROW ); + xModel->unlockControllers(); + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +ConverterRoot::ConverterRoot( + XmlFilterBase& rFilter, + ChartConverter& rChartConverter, + const ChartSpaceModel& rChartModel, + const Reference< XChartDocument >& rxChartDoc, + const Size& rChartSize ) : + mxData( new ConverterData( rFilter, rChartConverter, rChartModel, rxChartDoc, rChartSize ) ) +{ +} + +ConverterRoot::~ConverterRoot() +{ +} + +Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const +{ + Reference< XInterface > xInt; + try + { + xInt = mxData->mrFilter.getGlobalFactory()->createInstance( rServiceName ); + } + catch( Exception& ) + { + } + OSL_ENSURE( xInt.is(), "ConverterRoot::createInstance - cannot create instance" ); + return xInt; +} + +XmlFilterBase& ConverterRoot::getFilter() const +{ + return mxData->mrFilter; +} + +ChartConverter& ConverterRoot::getChartConverter() const +{ + return mxData->mrConverter; +} + +Reference< XChartDocument > ConverterRoot::getChartDocument() const +{ + return mxData->mxDoc; +} + +const Size& ConverterRoot::getChartSize() const +{ + return mxData->maSize; +} + +ObjectFormatter& ConverterRoot::getFormatter() const +{ + return mxData->maFormatter; +} + +void ConverterRoot::registerTitleLayout( const Reference< XTitle >& rxTitle, + const ModelRef< LayoutModel >& rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx ) +{ + OSL_ENSURE( rxTitle.is(), "ConverterRoot::registerTitleLayout - missing title object" ); + TitleLayoutInfo& rTitleInfo = mxData->maTitles[ TitleKey( eObjType, nMainIdx, nSubIdx ) ]; + OSL_ENSURE( rTitleInfo.mpGetShape, "ConverterRoot::registerTitleLayout - invalid title key" ); + rTitleInfo.mxTitle = rxTitle; + rTitleInfo.mxLayout = rxLayout; +} + +void ConverterRoot::convertTitlePositions() +{ + try + { + Reference< cssc::XChartDocument > xChart1Doc( mxData->mxDoc, UNO_QUERY_THROW ); + for( ConverterData::TitleMap::iterator aIt = mxData->maTitles.begin(), aEnd = mxData->maTitles.end(); aIt != aEnd; ++aIt ) + aIt->second.convertTitlePos( *this, xChart1Doc ); + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +namespace { + +/** Returns a position value in the chart area in 1/100 mm. */ +sal_Int32 lclCalcPosition( sal_Int32 nChartSize, double fPos, sal_Int32 nPosMode ) +{ + switch( nPosMode ) + { + case XML_edge: // absolute start position as factor of chart size + return getLimitedValue< sal_Int32, double >( nChartSize * fPos + 0.5, 0, nChartSize ); + case XML_factor: // position relative to object default position + OSL_ENSURE( false, "lclCalcPosition - relative positioning not supported" ); + return -1; + }; + + OSL_ENSURE( false, "lclCalcPosition - unknown positioning mode" ); + return -1; +} + +/** Returns a size value in the chart area in 1/100 mm. */ +sal_Int32 lclCalcSize( sal_Int32 nPos, sal_Int32 nChartSize, double fSize, sal_Int32 nSizeMode ) +{ + sal_Int32 nValue = getLimitedValue< sal_Int32, double >( nChartSize * fSize + 0.5, 0, nChartSize ); + switch( nSizeMode ) + { + case XML_factor: // size as factor of chart size + return nValue; + case XML_edge: // absolute end position as factor of chart size + return nValue - nPos + 1; + }; + + OSL_ENSURE( false, "lclCalcSize - unknown size mode" ); + return -1; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +LayoutConverter::LayoutConverter( const ConverterRoot& rParent, LayoutModel& rModel ) : + ConverterBase< LayoutModel >( rParent, rModel ) +{ +} + +LayoutConverter::~LayoutConverter() +{ +} + +bool LayoutConverter::calcAbsRectangle( Rectangle& orRect ) const +{ + if( !mrModel.mbAutoLayout ) + { + const Size& rChartSize = getChartSize(); + orRect.X = lclCalcPosition( rChartSize.Width, mrModel.mfX, mrModel.mnXMode ); + orRect.Y = lclCalcPosition( rChartSize.Height, mrModel.mfY, mrModel.mnYMode ); + if( (orRect.X >= 0) && (orRect.Y >= 0) ) + { + orRect.Width = lclCalcSize( orRect.X, rChartSize.Width, mrModel.mfW, mrModel.mnWMode ); + orRect.Height = lclCalcSize( orRect.Y, rChartSize.Height, mrModel.mfH, mrModel.mnHMode ); + return (orRect.Width > 0) && (orRect.Height > 0); + } + } + return false; +} + +bool LayoutConverter::convertFromModel( PropertySet& rPropSet ) +{ + if( !mrModel.mbAutoLayout && + (mrModel.mnXMode == XML_edge) && (mrModel.mfX >= 0.0) && + (mrModel.mnYMode == XML_edge) && (mrModel.mfY >= 0.0) ) + { + RelativePosition aPos; + aPos.Primary = getLimitedValue< double, double >( mrModel.mfX, 0.0, 1.0 ); + aPos.Secondary = getLimitedValue< double, double >( mrModel.mfY, 0.0, 1.0 ); + aPos.Anchor = ::com::sun::star::drawing::Alignment_TOP_LEFT; + rPropSet.setProperty( PROP_RelativePosition, aPos ); + return true; + } + return false; +} + +bool LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle ) +{ + if( !mrModel.mbAutoLayout ) + { + const Size& rChartSize = getChartSize(); + Point aShapePos( + lclCalcPosition( rChartSize.Width, mrModel.mfX, mrModel.mnXMode ), + lclCalcPosition( rChartSize.Height, mrModel.mfY, mrModel.mnYMode ) ); + if( (aShapePos.X >= 0) && (aShapePos.Y >= 0) ) + { + // the call to XShape.getSize() may recalc the chart view + Size aShapeSize = rxShape->getSize(); + // rotated shapes need special handling... + double fSin = fabs( sin( fRotationAngle * F_PI180 ) ); + // add part of height to X direction, if title is rotated down + if( fRotationAngle > 180.0 ) + aShapePos.X += static_cast< sal_Int32 >( fSin * aShapeSize.Height + 0.5 ); + // add part of width to Y direction, if title is rotated up + else if( fRotationAngle > 0.0 ) + aShapePos.Y += static_cast< sal_Int32 >( fSin * aShapeSize.Width + 0.5 ); + // set the resulting position at the shape + rxShape->setPosition( aShapePos ); + return true; + } + } + return false; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/datasourcecontext.cxx b/oox/source/drawingml/chart/datasourcecontext.cxx new file mode 100644 index 000000000000..d55b955d6e0d --- /dev/null +++ b/oox/source/drawingml/chart/datasourcecontext.cxx @@ -0,0 +1,231 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/datasourcecontext.hxx" +#include "oox/drawingml/chart/datasourcemodel.hxx" + +using ::rtl::OUString; +using ::oox::core::ContextHandler2Helper; +using ::oox::core::ContextHandlerRef; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +DoubleSequenceContext::DoubleSequenceContext( ContextHandler2Helper& rParent, DataSequenceModel& rModel ) : + DataSequenceContextBase( rParent, rModel ), + mnPtIndex( -1 ) +{ +} + +DoubleSequenceContext::~DoubleSequenceContext() +{ +} + +ContextHandlerRef DoubleSequenceContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( numRef ): + switch( nElement ) + { + case C_TOKEN( f ): + case C_TOKEN( numCache ): + return this; + } + break; + + case C_TOKEN( numCache ): + case C_TOKEN( numLit ): + switch( nElement ) + { + case C_TOKEN( formatCode ): + return this; + case C_TOKEN( ptCount ): + mrModel.mnPointCount = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( pt ): + mnPtIndex = rAttribs.getInteger( XML_idx, -1 ); + return this; + } + break; + + case C_TOKEN( pt ): + switch( nElement ) + { + case C_TOKEN( v ): + return this; + } + break; + } + return 0; +} + +void DoubleSequenceContext::onEndElement( const OUString& rChars ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( f ): + mrModel.maFormula = rChars; + break; + case C_TOKEN( formatCode ): + mrModel.maFormatCode = rChars; + break; + case C_TOKEN( v ): + if( mnPtIndex >= 0 ) + mrModel.maData[ mnPtIndex ] <<= rChars.toDouble(); + break; + } +} + +// ============================================================================ + +StringSequenceContext::StringSequenceContext( ContextHandler2Helper& rParent, DataSequenceModel& rModel ) : + DataSequenceContextBase( rParent, rModel ) +{ +} + +StringSequenceContext::~StringSequenceContext() +{ +} + +ContextHandlerRef StringSequenceContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( multiLvlStrRef ): + switch( nElement ) + { + case C_TOKEN( f ): + return this; + } + break; + + case C_TOKEN( strRef ): + switch( nElement ) + { + case C_TOKEN( f ): + case C_TOKEN( strCache ): + return this; + } + break; + + case C_TOKEN( strCache ): + case C_TOKEN( strLit ): + switch( nElement ) + { + case C_TOKEN( ptCount ): + mrModel.mnPointCount = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( pt ): + mnPtIndex = rAttribs.getInteger( XML_idx, -1 ); + return this; + } + break; + + case C_TOKEN( pt ): + switch( nElement ) + { + case C_TOKEN( v ): + return this; + } + break; + } + return 0; +} + +void StringSequenceContext::onEndElement( const OUString& rChars ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( f ): + mrModel.maFormula = rChars; + break; + case C_TOKEN( v ): + if( mnPtIndex >= 0 ) + mrModel.maData[ mnPtIndex ] <<= rChars; + break; + } +} + +// ============================================================================ + +DataSourceContext::DataSourceContext( ContextHandler2Helper& rParent, DataSourceModel& rModel ) : + ContextBase< DataSourceModel >( rParent, rModel ) +{ +} + +DataSourceContext::~DataSourceContext() +{ +} + +ContextHandlerRef DataSourceContext::onCreateContext( sal_Int32 nElement, const AttributeList& ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( cat ): + case C_TOKEN( xVal ): + switch( nElement ) + { + case C_TOKEN( multiLvlStrRef ): + case C_TOKEN( strLit ): + case C_TOKEN( strRef ): + OSL_ENSURE( !mrModel.mxDataSeq, "DataSourceContext::onCreateContext - multiple data sequences" ); + return new StringSequenceContext( *this, mrModel.mxDataSeq.create() ); + + case C_TOKEN( numLit ): + case C_TOKEN( numRef ): + OSL_ENSURE( !mrModel.mxDataSeq, "DataSourceContext::onCreateContext - multiple data sequences" ); + return new DoubleSequenceContext( *this, mrModel.mxDataSeq.create() ); + } + break; + + case C_TOKEN( plus ): + case C_TOKEN( minus ): + case C_TOKEN( val ): + case C_TOKEN( yVal ): + case C_TOKEN( bubbleSize ): + switch( nElement ) + { + case C_TOKEN( numLit ): + case C_TOKEN( numRef ): + OSL_ENSURE( !mrModel.mxDataSeq, "DataSourceContext::onCreateContext - multiple data sequences" ); + return new DoubleSequenceContext( *this, mrModel.mxDataSeq.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/datasourceconverter.cxx b/oox/source/drawingml/chart/datasourceconverter.cxx new file mode 100644 index 000000000000..2409f8e89962 --- /dev/null +++ b/oox/source/drawingml/chart/datasourceconverter.cxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/datasourceconverter.hxx" +#include <com/sun/star/chart2/XChartDocument.hpp> +#include "oox/drawingml/chart/chartconverter.hxx" +#include "oox/drawingml/chart/datasourcemodel.hxx" +#include "properties.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::chart2::data::XDataSequence; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +DataSequenceConverter::DataSequenceConverter( const ConverterRoot& rParent, DataSequenceModel& rModel ) : + ConverterBase< DataSequenceModel >( rParent, rModel ) +{ +} + +DataSequenceConverter::~DataSequenceConverter() +{ +} + +Reference< XDataSequence > DataSequenceConverter::createDataSequence( const OUString& rRole ) +{ + // create data sequence from data source model (virtual call at chart converter) + Reference< XDataSequence > xDataSeq = getChartConverter().createDataSequence( getChartDocument()->getDataProvider(), mrModel ); + + // set sequence role + PropertySet aSeqProp( xDataSeq ); + aSeqProp.setProperty( PROP_Role, rRole ); + + return xDataSeq; +} + +// ============================================================================ + +DataSourceConverter::DataSourceConverter( const ConverterRoot& rParent, DataSourceModel& rModel ) : + ConverterBase< DataSourceModel >( rParent, rModel ) +{ +} + +DataSourceConverter::~DataSourceConverter() +{ +} + +Reference< XDataSequence > DataSourceConverter::createDataSequence( const OUString& rRole ) +{ + Reference< XDataSequence > xDataSeq; + if( mrModel.mxDataSeq.is() ) + { + DataSequenceConverter aDataSeqConv( *this, *mrModel.mxDataSeq ); + xDataSeq = aDataSeqConv.createDataSequence( rRole ); + } + return xDataSeq; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/datasourcemodel.cxx b/oox/source/drawingml/chart/datasourcemodel.cxx new file mode 100644 index 000000000000..1f5b15f3e809 --- /dev/null +++ b/oox/source/drawingml/chart/datasourcemodel.cxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/datasourcemodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +DataSequenceModel::DataSequenceModel() : + mnPointCount( -1 ) +{ +} + +DataSequenceModel::~DataSequenceModel() +{ +} + +// ============================================================================ + +DataSourceModel::DataSourceModel() +{ +} + +DataSourceModel::~DataSourceModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/makefile.mk b/oox/source/drawingml/chart/makefile.mk new file mode 100644 index 000000000000..84762e6a2540 --- /dev/null +++ b/oox/source/drawingml/chart/makefile.mk @@ -0,0 +1,74 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=oox +TARGET=chart +AUTOSEG=true + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE: $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/axiscontext.obj \ + $(SLO)$/axisconverter.obj \ + $(SLO)$/axismodel.obj \ + $(SLO)$/chartcontextbase.obj \ + $(SLO)$/chartconverter.obj \ + $(SLO)$/chartdrawingfragment.obj \ + $(SLO)$/chartspaceconverter.obj \ + $(SLO)$/chartspacefragment.obj \ + $(SLO)$/chartspacemodel.obj \ + $(SLO)$/converterbase.obj \ + $(SLO)$/datasourcecontext.obj \ + $(SLO)$/datasourceconverter.obj \ + $(SLO)$/datasourcemodel.obj \ + $(SLO)$/modelbase.obj \ + $(SLO)$/objectformatter.obj \ + $(SLO)$/plotareacontext.obj \ + $(SLO)$/plotareaconverter.obj \ + $(SLO)$/plotareamodel.obj \ + $(SLO)$/seriescontext.obj \ + $(SLO)$/seriesconverter.obj \ + $(SLO)$/seriesmodel.obj \ + $(SLO)$/titlecontext.obj \ + $(SLO)$/titleconverter.obj \ + $(SLO)$/titlemodel.obj \ + $(SLO)$/typegroupcontext.obj \ + $(SLO)$/typegroupconverter.obj \ + $(SLO)$/typegroupmodel.obj + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk diff --git a/oox/source/drawingml/chart/modelbase.cxx b/oox/source/drawingml/chart/modelbase.cxx new file mode 100644 index 000000000000..c182d8e3e410 --- /dev/null +++ b/oox/source/drawingml/chart/modelbase.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/modelbase.hxx" +#include "oox/helper/attributelist.hxx" + +using ::rtl::OUString; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +NumberFormat::NumberFormat() : + mbSourceLinked( true ) +{ +} + +void NumberFormat::setAttributes( const AttributeList& rAttribs ) +{ + maFormatCode = rAttribs.getString( XML_formatCode, OUString() ); + // default is 'false', not 'true' as specified + mbSourceLinked = rAttribs.getBool( XML_sourceLinked, false ); +} + +// ============================================================================ + +LayoutModel::LayoutModel() : + mfX( 0.0 ), + mfY( 0.0 ), + mfW( 0.0 ), + mfH( 0.0 ), + mnXMode( XML_factor ), + mnYMode( XML_factor ), + mnWMode( XML_factor ), + mnHMode( XML_factor ), + mnTarget( XML_outer ), + mbAutoLayout( true ) +{ +} + +LayoutModel::~LayoutModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/objectformatter.cxx b/oox/source/drawingml/chart/objectformatter.cxx new file mode 100644 index 000000000000..d96e2d43dd6f --- /dev/null +++ b/oox/source/drawingml/chart/objectformatter.cxx @@ -0,0 +1,1214 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/objectformatter.hxx" +#include <rtl/strbuf.hxx> +#include <osl/thread.h> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include "properties.hxx" +#include "tokens.hxx" +#include "oox/helper/modelobjecthelper.hxx" +#include "oox/core/xmlfilterbase.hxx" +#include "oox/drawingml/fillproperties.hxx" +#include "oox/drawingml/lineproperties.hxx" +#include "oox/drawingml/textbody.hxx" +#include "oox/drawingml/textparagraph.hxx" +#include "oox/drawingml/theme.hxx" +#include "oox/drawingml/chart/chartspacemodel.hxx" + +using ::rtl::OStringBuffer; +using ::rtl::OUString; +using ::rtl::OUStringToOString; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::lang::Locale; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::frame::XModel; +using ::com::sun::star::chart2::XChartDocument; +using ::com::sun::star::graphic::XGraphic; +using ::com::sun::star::util::XNumberFormats; +using ::com::sun::star::util::XNumberFormatsSupplier; +using ::com::sun::star::util::XNumberFormatTypes; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +struct AutoFormatPatternEntry +{ + sal_Int32 mnColorToken; /// Theme color token. + sal_Int32 mnModToken; /// Color modification token. + sal_Int32 mnModValue; /// Color modification value. +}; + +#define AUTOFORMAT_PATTERN_COLOR( color_token ) \ + { color_token, XML_TOKEN_INVALID, 0 } + +#define AUTOFORMAT_PATTERN_COLORMOD( color_token, mod_token, mod_value ) \ + { color_token, mod_token, mod_value } + +#define AUTOFORMAT_PATTERN_END() \ + AUTOFORMAT_PATTERN_COLOR( XML_TOKEN_INVALID ) + +static const AutoFormatPatternEntry spAutoFormatPattern1[] = +{ + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 88500 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 55000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 78000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 92500 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 70000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 30000 ), + AUTOFORMAT_PATTERN_END() +}; + +static const AutoFormatPatternEntry spAutoFormatPattern2[] = +{ + AUTOFORMAT_PATTERN_COLOR( XML_accent1 ), + AUTOFORMAT_PATTERN_COLOR( XML_accent2 ), + AUTOFORMAT_PATTERN_COLOR( XML_accent3 ), + AUTOFORMAT_PATTERN_COLOR( XML_accent4 ), + AUTOFORMAT_PATTERN_COLOR( XML_accent5 ), + AUTOFORMAT_PATTERN_COLOR( XML_accent6 ), + AUTOFORMAT_PATTERN_END() +}; + +static const AutoFormatPatternEntry spAutoFormatPattern3[] = +{ + AUTOFORMAT_PATTERN_COLORMOD( XML_accent1, XML_shade, 50000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_accent2, XML_shade, 50000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_accent3, XML_shade, 50000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_accent4, XML_shade, 50000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_accent5, XML_shade, 50000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_accent6, XML_shade, 50000 ), + AUTOFORMAT_PATTERN_END() +}; + +static const AutoFormatPatternEntry spAutoFormatPattern4[] = +{ + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 5000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 55000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 78000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 15000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 70000 ), + AUTOFORMAT_PATTERN_COLORMOD( XML_dk1, XML_tint, 30000 ), + AUTOFORMAT_PATTERN_END() +}; + +#undef AUTOFORMAT_PATTERN_COLOR +#undef AUTOFORMAT_PATTERN_COLORMOD +#undef AUTOFORMAT_PATTERN_END + +// ---------------------------------------------------------------------------- + +struct AutoFormatEntry +{ + sal_Int32 mnFirstStyleIdx; /// First chart style index. + sal_Int32 mnLastStyleIdx; /// Last chart style index. + sal_Int32 mnThemedIdx; /// Themed style index. + sal_Int32 mnColorToken; /// Theme color token. + sal_Int32 mnModToken; /// Color modification token. + sal_Int32 mnModValue; /// Color modification value. + sal_Int32 mnRelLineWidth; /// Relative line width (percent). + const AutoFormatPatternEntry* mpPattern;/// Color cycling pattern for data series. + bool mbFadedColor; /// True = Faded color for data series. +}; + +#define AUTOFORMAT_COLOR( first, last, themed_style, color_token ) \ + { first, last, themed_style, color_token, XML_TOKEN_INVALID, 0, 100, 0, false } + +#define AUTOFORMAT_ACCENTS( first, themed_style ) \ + AUTOFORMAT_COLOR( first, first, themed_style, XML_accent1 ), \ + AUTOFORMAT_COLOR( first + 1, first + 1, themed_style, XML_accent2 ), \ + AUTOFORMAT_COLOR( first + 2, first + 2, themed_style, XML_accent3 ), \ + AUTOFORMAT_COLOR( first + 3, first + 3, themed_style, XML_accent4 ), \ + AUTOFORMAT_COLOR( first + 4, first + 4, themed_style, XML_accent5 ), \ + AUTOFORMAT_COLOR( first + 5, first + 5, themed_style, XML_accent6 ) + +#define AUTOFORMAT_COLORMOD( first, last, themed_style, color_token, mod_token, mod_value ) \ + { first, last, themed_style, color_token, mod_token, mod_value, 100, 0, false } + +#define AUTOFORMAT_ACCENTSMOD( first, themed_style, mod_token, mod_value ) \ + AUTOFORMAT_COLORMOD( first, first, themed_style, XML_accent1, mod_token, mod_value ), \ + AUTOFORMAT_COLORMOD( first + 1, first + 1, themed_style, XML_accent2, mod_token, mod_value ), \ + AUTOFORMAT_COLORMOD( first + 2, first + 2, themed_style, XML_accent3, mod_token, mod_value ), \ + AUTOFORMAT_COLORMOD( first + 3, first + 3, themed_style, XML_accent4, mod_token, mod_value ), \ + AUTOFORMAT_COLORMOD( first + 4, first + 4, themed_style, XML_accent5, mod_token, mod_value ), \ + AUTOFORMAT_COLORMOD( first + 5, first + 5, themed_style, XML_accent6, mod_token, mod_value ) + +#define AUTOFORMAT_PATTERN( first, last, themed_style, line_width, pattern ) \ + { first, last, themed_style, XML_TOKEN_INVALID, XML_TOKEN_INVALID, 0, line_width, pattern, false } + +#define AUTOFORMAT_FADED( first, last, themed_style, color_token, line_width ) \ + { first, last, themed_style, color_token, XML_TOKEN_INVALID, 0, line_width, 0, true } + +#define AUTOFORMAT_FADEDACCENTS( first, themed_style, line_width ) \ + AUTOFORMAT_FADED( first, first, themed_style, XML_accent1, line_width ), \ + AUTOFORMAT_FADED( first + 1, first + 1, themed_style, XML_accent2, line_width ), \ + AUTOFORMAT_FADED( first + 2, first + 2, themed_style, XML_accent3, line_width ), \ + AUTOFORMAT_FADED( first + 3, first + 3, themed_style, XML_accent4, line_width ), \ + AUTOFORMAT_FADED( first + 4, first + 4, themed_style, XML_accent5, line_width ), \ + AUTOFORMAT_FADED( first + 5, first + 5, themed_style, XML_accent6, line_width ) + +#define AUTOFORMAT_INVISIBLE( first, last ) \ + AUTOFORMAT_COLOR( first, last, -1, XML_TOKEN_INVALID ) + +#define AUTOFORMAT_END() \ + AUTOFORMAT_INVISIBLE( -1, -1 ) + +static const AutoFormatEntry spNoFormats[] = +{ + AUTOFORMAT_INVISIBLE( 1, 48 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spChartSpaceLines[] = +{ + AUTOFORMAT_COLORMOD( 1, 32, THEMED_STYLE_SUBTLE, XML_tx1, XML_tint, 75000 ), + AUTOFORMAT_COLORMOD( 33, 40, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 75000 ), + // 41...48: no line, same as Chart2 + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spChartSpaceFills[] = +{ + AUTOFORMAT_COLOR( 1, 32, THEMED_STYLE_SUBTLE, XML_bg1 ), + AUTOFORMAT_COLOR( 33, 40, THEMED_STYLE_SUBTLE, XML_lt1 ), + AUTOFORMAT_COLOR( 41, 48, THEMED_STYLE_SUBTLE, XML_dk1 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spPlotArea2dFills[] = +{ + AUTOFORMAT_COLOR( 1, 32, THEMED_STYLE_SUBTLE, XML_bg1 ), + AUTOFORMAT_COLORMOD( 33, 34, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 20000 ), + AUTOFORMAT_ACCENTSMOD( 35, THEMED_STYLE_SUBTLE, XML_tint, 20000 ), // tint not documented!? + AUTOFORMAT_COLORMOD( 41, 48, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spFloorLines[] = +{ + AUTOFORMAT_COLORMOD( 1, 32, THEMED_STYLE_SUBTLE, XML_tx1, XML_tint, 75000 ), + AUTOFORMAT_COLORMOD( 33, 40, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 75000 ), + // 41...48: no line, same as Chart2 + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spWallFloorFills[] = +{ + AUTOFORMAT_INVISIBLE( 1, 32 ), + AUTOFORMAT_COLORMOD( 33, 34, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 20000 ), + AUTOFORMAT_ACCENTSMOD( 35, THEMED_STYLE_SUBTLE, XML_tint, 20000 ), // tint not documented!? + AUTOFORMAT_COLORMOD( 41, 48, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spAxisLines[] = +{ + AUTOFORMAT_COLORMOD( 1, 32, THEMED_STYLE_SUBTLE, XML_tx1, XML_tint, 75000 ), // tint not documented!? + AUTOFORMAT_COLORMOD( 33, 48, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 75000 ), // tint not documented!? + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spMajorGridLines[] = +{ + AUTOFORMAT_COLORMOD( 1, 32, THEMED_STYLE_SUBTLE, XML_tx1, XML_tint, 75000 ), // tint not documented!? + AUTOFORMAT_COLORMOD( 33, 48, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 75000 ), // tint not documented!? + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spMinorGridLines[] = +{ + AUTOFORMAT_COLORMOD( 1, 40, THEMED_STYLE_SUBTLE, XML_tx1, XML_tint, 50000 ), + AUTOFORMAT_COLORMOD( 41, 48, THEMED_STYLE_SUBTLE, XML_tx1, XML_tint, 90000 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spOtherLines[] = +{ + AUTOFORMAT_COLOR( 1, 32, THEMED_STYLE_SUBTLE, XML_tx1 ), + AUTOFORMAT_COLOR( 33, 34, THEMED_STYLE_SUBTLE, XML_dk1 ), + AUTOFORMAT_COLORMOD( 35, 40, THEMED_STYLE_SUBTLE, XML_dk1, XML_shade, 25000 ), + AUTOFORMAT_COLOR( 41, 48, THEMED_STYLE_SUBTLE, XML_lt1 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spLinearSeriesLines[] = +{ + AUTOFORMAT_PATTERN( 1, 1, THEMED_STYLE_SUBTLE, 300, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 2, 2, THEMED_STYLE_SUBTLE, 300, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 3, THEMED_STYLE_SUBTLE, 300 ), + AUTOFORMAT_PATTERN( 9, 9, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 10, 10, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 11, THEMED_STYLE_SUBTLE, 500 ), + AUTOFORMAT_PATTERN( 17, 17, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 18, 18, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 19, THEMED_STYLE_SUBTLE, 500 ), + AUTOFORMAT_PATTERN( 25, 25, THEMED_STYLE_SUBTLE, 700, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 26, 26, THEMED_STYLE_SUBTLE, 700, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 27, THEMED_STYLE_SUBTLE, 700 ), + AUTOFORMAT_PATTERN( 33, 33, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 34, 34, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 35, THEMED_STYLE_SUBTLE, 500 ), + AUTOFORMAT_PATTERN( 41, 42, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern4 ), + AUTOFORMAT_PATTERN( 42, 42, THEMED_STYLE_SUBTLE, 500, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 43, THEMED_STYLE_SUBTLE, 500 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spFilledSeriesLines[] = +{ + AUTOFORMAT_INVISIBLE( 1, 8 ), + AUTOFORMAT_COLOR( 9, 16, THEMED_STYLE_SUBTLE, XML_lt1 ), + AUTOFORMAT_INVISIBLE( 17, 32 ), + AUTOFORMAT_COLORMOD( 33, 33, THEMED_STYLE_SUBTLE, XML_dk1, XML_shade, 50000 ), + AUTOFORMAT_PATTERN( 34, 34, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern3 ), + AUTOFORMAT_ACCENTSMOD( 35, THEMED_STYLE_SUBTLE, XML_shade, 50000 ), + AUTOFORMAT_INVISIBLE( 41, 48 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spFilledSeries2dFills[] = +{ + AUTOFORMAT_PATTERN( 1, 1, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 2, 2, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 3, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 9, 9, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 10, 10, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 11, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 17, 17, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 18, 18, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 19, THEMED_STYLE_INTENSE, 100 ), + AUTOFORMAT_PATTERN( 25, 25, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 26, 26, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 27, THEMED_STYLE_INTENSE, 100 ), + AUTOFORMAT_PATTERN( 33, 33, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 34, 34, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 35, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 41, 42, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern4 ), + AUTOFORMAT_PATTERN( 42, 42, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 43, THEMED_STYLE_INTENSE, 100 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spFilledSeries3dFills[] = +{ + AUTOFORMAT_PATTERN( 1, 1, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 2, 2, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 3, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 9, 9, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 10, 10, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 11, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 17, 17, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 18, 18, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 19, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 25, 25, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 26, 26, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 27, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 33, 33, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern1 ), + AUTOFORMAT_PATTERN( 34, 34, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 35, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_PATTERN( 41, 42, THEMED_STYLE_SUBTLE, 100, spAutoFormatPattern4 ), + AUTOFORMAT_PATTERN( 42, 42, THEMED_STYLE_INTENSE, 100, spAutoFormatPattern2 ), + AUTOFORMAT_FADEDACCENTS( 43, THEMED_STYLE_SUBTLE, 100 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spFilledSeriesEffects[] = +{ + // 1...8: no effect, same as Chart2 + AUTOFORMAT_COLOR( 9, 16, THEMED_STYLE_SUBTLE, XML_dk1 ), + AUTOFORMAT_COLOR( 17, 24, THEMED_STYLE_MODERATE, XML_dk1 ), + AUTOFORMAT_COLOR( 25, 32, THEMED_STYLE_INTENSE, XML_dk1 ), + // 33...40: no effect, same as Chart2 + AUTOFORMAT_COLOR( 41, 48, THEMED_STYLE_INTENSE, XML_dk1 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spUpDownBarLines[] = +{ + AUTOFORMAT_COLOR( 1, 16, THEMED_STYLE_SUBTLE, XML_tx1 ), + AUTOFORMAT_INVISIBLE( 17, 32 ), + AUTOFORMAT_COLOR( 33, 34, THEMED_STYLE_SUBTLE, XML_dk1 ), + AUTOFORMAT_ACCENTSMOD( 35, THEMED_STYLE_SUBTLE, XML_shade, 25000 ), + AUTOFORMAT_INVISIBLE( 41, 48 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spUpBarFills[] = +{ + AUTOFORMAT_COLORMOD( 1, 1, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 2, 2, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 5000 ), + AUTOFORMAT_ACCENTSMOD( 3, THEMED_STYLE_SUBTLE, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 9, 9, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 10, 10, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 5000 ), + AUTOFORMAT_ACCENTSMOD( 11, THEMED_STYLE_SUBTLE, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 17, 17, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 18, 18, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 5000 ), + AUTOFORMAT_ACCENTSMOD( 19, THEMED_STYLE_INTENSE, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 25, 25, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 25000 ), + AUTOFORMAT_COLORMOD( 26, 26, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 5000 ), + AUTOFORMAT_ACCENTSMOD( 27, THEMED_STYLE_INTENSE, XML_tint, 25000 ), + AUTOFORMAT_COLOR( 33, 40, THEMED_STYLE_SUBTLE, XML_lt1 ), + AUTOFORMAT_COLORMOD( 41, 41, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 25000 ), + AUTOFORMAT_COLOR( 42, 42, THEMED_STYLE_INTENSE, XML_lt1 ), + AUTOFORMAT_ACCENTSMOD( 43, THEMED_STYLE_INTENSE, XML_tint, 25000 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spDownBarFills[] = +{ + AUTOFORMAT_COLORMOD( 1, 1, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 85000 ), + AUTOFORMAT_COLORMOD( 2, 2, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_ACCENTSMOD( 3, THEMED_STYLE_SUBTLE, XML_shade, 25000 ), + AUTOFORMAT_COLORMOD( 9, 9, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 85000 ), + AUTOFORMAT_COLORMOD( 10, 10, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_ACCENTSMOD( 11, THEMED_STYLE_SUBTLE, XML_shade, 25000 ), + AUTOFORMAT_COLORMOD( 17, 17, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 85000 ), + AUTOFORMAT_COLORMOD( 18, 18, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_ACCENTSMOD( 19, THEMED_STYLE_INTENSE, XML_shade, 25000 ), + AUTOFORMAT_COLORMOD( 25, 25, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 85000 ), + AUTOFORMAT_COLORMOD( 26, 26, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_ACCENTSMOD( 27, THEMED_STYLE_INTENSE, XML_shade, 25000 ), + AUTOFORMAT_COLORMOD( 33, 33, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 85000 ), + AUTOFORMAT_COLORMOD( 34, 34, THEMED_STYLE_SUBTLE, XML_dk1, XML_tint, 95000 ), + AUTOFORMAT_ACCENTSMOD( 27, THEMED_STYLE_SUBTLE, XML_shade, 25000 ), + AUTOFORMAT_COLORMOD( 41, 41, THEMED_STYLE_INTENSE, XML_dk1, XML_tint, 85000 ), + AUTOFORMAT_COLOR( 42, 42, THEMED_STYLE_INTENSE, XML_dk1 ), + AUTOFORMAT_ACCENTSMOD( 43, THEMED_STYLE_INTENSE, XML_shade, 25000 ), + AUTOFORMAT_END() +}; + +static const AutoFormatEntry spUpDownBarEffects[] = +{ + // 1...8: no effect, same as Chart2 + AUTOFORMAT_COLOR( 9, 16, THEMED_STYLE_SUBTLE, XML_dk1 ), + AUTOFORMAT_COLOR( 17, 24, THEMED_STYLE_MODERATE, XML_dk1 ), + AUTOFORMAT_COLOR( 25, 32, THEMED_STYLE_INTENSE, XML_dk1 ), + // 33...40: no effect, same as Chart2 + AUTOFORMAT_COLOR( 41, 48, THEMED_STYLE_INTENSE, XML_dk1 ), + AUTOFORMAT_END() +}; + +#undef AUTOFORMAT_COLOR +#undef AUTOFORMAT_ACCENTS +#undef AUTOFORMAT_COLORMOD +#undef AUTOFORMAT_ACCENTSMOD +#undef AUTOFORMAT_PATTERN +#undef AUTOFORMAT_FADED +#undef AUTOFORMAT_FADEDACCENTS +#undef AUTOFORMAT_INVISIBLE +#undef AUTOFORMAT_END + +const AutoFormatEntry* lclGetAutoFormatEntry( const AutoFormatEntry* pEntries, sal_Int32 nStyle ) +{ + for( ; pEntries && (pEntries->mnFirstStyleIdx >= 0); ++pEntries ) + if( (pEntries->mnFirstStyleIdx <= nStyle) && (nStyle <= pEntries->mnLastStyleIdx) ) + return pEntries; + return 0; +} + +// ---------------------------------------------------------------------------- + +struct AutoTextEntry +{ + sal_Int32 mnFirstStyleIdx; /// First chart style index. + sal_Int32 mnLastStyleIdx; /// Last chart style index. + sal_Int32 mnThemedFont; /// Themed font (minor/major). + sal_Int32 mnColorToken; /// Theme color token. + sal_Int32 mnDefFontSize; /// Default font size (1/100 points). + sal_Int32 mnRelFontSize; /// Font size relative to chart global font (percent). + bool mbBold; /// True = bold font. +}; + +#define AUTOTEXT_COLOR( first, last, themed_font, color_token, def_font_size, rel_font_size, bold ) \ + { first, last, themed_font, color_token, def_font_size, rel_font_size, bold } + +#define AUTOTEXT_END() \ + AUTOTEXT_COLOR( -1, -1, XML_none, XML_TOKEN_INVALID, 1000, 100, false ) + +static const AutoTextEntry spChartTitleTexts[] = +{ + AUTOTEXT_COLOR( 1, 40, XML_minor, XML_tx1, 1800, 120, true ), + AUTOTEXT_COLOR( 41, 48, XML_minor, XML_lt1, 1800, 120, true ), + AUTOTEXT_END() +}; + +static const AutoTextEntry spAxisTitleTexts[] = +{ + AUTOTEXT_COLOR( 1, 40, XML_minor, XML_tx1, 1000, 100, true ), + AUTOTEXT_COLOR( 41, 48, XML_minor, XML_lt1, 1000, 100, true ), + AUTOTEXT_END() +}; + +static const AutoTextEntry spOtherTexts[] = +{ + AUTOTEXT_COLOR( 1, 40, XML_minor, XML_tx1, 1000, 100, false ), + AUTOTEXT_COLOR( 41, 48, XML_minor, XML_lt1, 1000, 100, false ), + AUTOTEXT_END() +}; + +#undef AUTOTEXT_COLOR +#undef AUTOTEXT_END + +const AutoTextEntry* lclGetAutoTextEntry( const AutoTextEntry* pEntries, sal_Int32 nStyle ) +{ + for( ; pEntries && (pEntries->mnFirstStyleIdx >= 0); ++pEntries ) + if( (pEntries->mnFirstStyleIdx <= nStyle) && (nStyle <= pEntries->mnLastStyleIdx) ) + return pEntries; + return 0; +} + +// ---------------------------------------------------------------------------- + +/** Enumerates different sets of property names for chart object formatting. */ +enum PropertyType +{ + PROPERTYTYPE_COMMON, /// Common objects, no special handling. + PROPERTYTYPE_LINEARSERIES, /// Specific to linear data series. + PROPERTYTYPE_FILLEDSERIES /// Specific to filled data series. +}; + +/** Contains information about formatting of a specific chart object type. */ +struct ObjectTypeFormatEntry +{ + ObjectType meObjType; /// Object type for automatic format. + PropertyType mePropType; /// Property type for property names. + const AutoFormatEntry* mpAutoLines; /// Automatic line formatting for all chart styles. + const AutoFormatEntry* mpAutoFills; /// Automatic fill formatting for all chart styles. + const AutoFormatEntry* mpAutoEffects; /// Automatic effect formatting for all chart styles. + const AutoTextEntry* mpAutoTexts; /// Automatic text attributes for all chart styles. + bool mbIsFrame; /// True = object is a frame, false = object is a line. +}; + +#define TYPEFORMAT_FRAME( obj_type, prop_type, auto_texts, auto_lines, auto_fills, auto_effects ) \ + { obj_type, prop_type, auto_lines, auto_fills, auto_effects, auto_texts, true } + +#define TYPEFORMAT_LINE( obj_type, prop_type, auto_texts, auto_lines ) \ + { obj_type, prop_type, auto_lines, 0, 0, auto_texts, false } + +static const ObjectTypeFormatEntry spObjTypeFormatEntries[] = +{ + // object type property type auto text auto line auto fill auto effect + TYPEFORMAT_FRAME( OBJECTTYPE_CHARTSPACE, PROPERTYTYPE_COMMON, 0, spChartSpaceLines, spChartSpaceFills, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_CHARTTITLE, PROPERTYTYPE_COMMON, spChartTitleTexts, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_LEGEND, PROPERTYTYPE_COMMON, spOtherTexts, spNoFormats, spNoFormats, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_PLOTAREA2D, PROPERTYTYPE_COMMON, 0, 0 /* eq to Ch2 */, spPlotArea2dFills, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_PLOTAREA3D, PROPERTYTYPE_COMMON, 0, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_WALL, PROPERTYTYPE_COMMON, 0, 0 /* eq to Ch2 */, spWallFloorFills, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_FLOOR, PROPERTYTYPE_COMMON, 0, spFloorLines, spWallFloorFills, 0 /* eq to Ch2 */ ), + TYPEFORMAT_LINE( OBJECTTYPE_AXIS, PROPERTYTYPE_COMMON, spOtherTexts, spAxisLines ), + TYPEFORMAT_FRAME( OBJECTTYPE_AXISTITLE, PROPERTYTYPE_COMMON, spAxisTitleTexts, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */ ), + TYPEFORMAT_FRAME( OBJECTTYPE_AXISUNIT, PROPERTYTYPE_COMMON, spAxisTitleTexts, 0 /* eq in Ch2 */, 0 /* eq in Ch2 */, 0 /* eq in Ch2 */ ), + TYPEFORMAT_LINE( OBJECTTYPE_MAJORGRIDLINE, PROPERTYTYPE_COMMON, 0, spMajorGridLines ), + TYPEFORMAT_LINE( OBJECTTYPE_MINORGRIDLINE, PROPERTYTYPE_COMMON, 0, spMinorGridLines ), + TYPEFORMAT_LINE( OBJECTTYPE_LINEARSERIES2D, PROPERTYTYPE_LINEARSERIES, 0, spLinearSeriesLines ), + TYPEFORMAT_FRAME( OBJECTTYPE_FILLEDSERIES2D, PROPERTYTYPE_FILLEDSERIES, 0, spFilledSeriesLines, spFilledSeries2dFills, spFilledSeriesEffects ), + TYPEFORMAT_FRAME( OBJECTTYPE_FILLEDSERIES3D, PROPERTYTYPE_FILLEDSERIES, 0, spFilledSeriesLines, spFilledSeries3dFills, spFilledSeriesEffects ), + TYPEFORMAT_FRAME( OBJECTTYPE_DATALABEL, PROPERTYTYPE_COMMON, spOtherTexts, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */ ), + TYPEFORMAT_LINE( OBJECTTYPE_TRENDLINE, PROPERTYTYPE_COMMON, 0, spOtherLines ), + TYPEFORMAT_FRAME( OBJECTTYPE_TRENDLINELABEL, PROPERTYTYPE_COMMON, spOtherTexts, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */, 0 /* eq to Ch2 */ ), + TYPEFORMAT_LINE( OBJECTTYPE_ERRORBAR, PROPERTYTYPE_COMMON, 0, spOtherLines ), + TYPEFORMAT_LINE( OBJECTTYPE_SERLINE, PROPERTYTYPE_COMMON, 0, spOtherLines ), + TYPEFORMAT_LINE( OBJECTTYPE_LEADERLINE, PROPERTYTYPE_COMMON, 0, spOtherLines ), + TYPEFORMAT_LINE( OBJECTTYPE_DROPLINE, PROPERTYTYPE_COMMON, 0, spOtherLines ), + TYPEFORMAT_LINE( OBJECTTYPE_HILOLINE, PROPERTYTYPE_LINEARSERIES, 0, spOtherLines ), + TYPEFORMAT_FRAME( OBJECTTYPE_UPBAR, PROPERTYTYPE_COMMON, 0, spUpDownBarLines, spUpBarFills, spUpDownBarEffects ), + TYPEFORMAT_FRAME( OBJECTTYPE_DOWNBAR, PROPERTYTYPE_COMMON, 0, spUpDownBarLines, spDownBarFills, spUpDownBarEffects ), + TYPEFORMAT_LINE( OBJECTTYPE_DATATABLE, PROPERTYTYPE_COMMON, spOtherTexts, spChartSpaceLines ) +}; + +#undef TYPEFORMAT_FRAME +#undef TYPEFORMAT_LINE +// ---------------------------------------------------------------------------- + +void lclConvertPictureOptions( FillProperties& orFillProps, const PictureOptionsModel& rPicOptions ) +{ + bool bStacked = (rPicOptions.mnPictureFormat == XML_stack) || (rPicOptions.mnPictureFormat == XML_stackScale); + orFillProps.maBlipProps.moBitmapMode = bStacked ? XML_tile : XML_stretch; +} + +// ---------------------------------------------------------------------------- + +const sal_Int32 spnCommonLineIds[ LineId_END ] = { PROP_LineStyle, PROP_LineWidth, PROP_LineColor, PROP_LineTransparence, PROP_LineDashName, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID }; +const sal_Int32 spnLinearLineIds[ LineId_END ] = { PROP_LineStyle, PROP_LineWidth, PROP_Color, PROP_Transparency, PROP_LineDashName, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID }; +const sal_Int32 spnFilledLineIds[ LineId_END ] = { PROP_BorderStyle, PROP_BorderWidth, PROP_BorderColor, PROP_BorderTransparency, PROP_BorderDashName, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID, PROP_INVALID }; + +const sal_Int32 spnCommonFillIds[ FillId_END ] = { PROP_FillStyle, PROP_FillColor, PROP_FillTransparence, PROP_FillGradientName, PROP_FillBitmapName, PROP_FillBitmapMode, PROP_FillBitmapSizeX, PROP_FillBitmapSizeY, PROP_FillBitmapPositionOffsetX, PROP_FillBitmapPositionOffsetY, PROP_FillBitmapRectanglePoint }; +const sal_Int32 spnFilledFillIds[ FillId_END ] = { PROP_FillStyle, PROP_Color, PROP_Transparency, PROP_GradientName, PROP_FillBitmapName, PROP_FillBitmapMode, PROP_FillBitmapSizeX, PROP_FillBitmapSizeY, PROP_FillBitmapPositionOffsetX, PROP_FillBitmapPositionOffsetY, PROP_FillBitmapRectanglePoint }; + +} // namespace + +// ============================================================================ + +struct ObjectFormatterData; + +// ---------------------------------------------------------------------------- + +class DetailFormatterBase +{ +public: + explicit DetailFormatterBase( + ObjectFormatterData& rData, + const AutoFormatEntry* pAutoFormatEntry ); + explicit DetailFormatterBase( + ObjectFormatterData& rData, + const AutoTextEntry* pAutoTextEntry ); + +protected: + /** Returns the placeholder color which may depend on the passed series index. */ + sal_Int32 getPhColor( sal_Int32 nSeriesIdx ) const; + +private: + /** Resolves and returns the scheme color with the passed transformation. */ + sal_Int32 getSchemeColor( sal_Int32 nColorToken, sal_Int32 nModToken, sal_Int32 nModValue ) const; + +protected: + typedef ::std::vector< sal_Int32 > ColorPatternVec; + + ObjectFormatterData& mrData; /// Shared formatter data. + sal_Int32 mnPhClr; /// RGB placeholder color for themed style. + ColorPatternVec maColorPattern; /// Different cycling colors for data series. +}; + +// ---------------------------------------------------------------------------- + +class LineFormatter : public DetailFormatterBase +{ +public: + explicit LineFormatter( + ObjectFormatterData& rData, + const AutoFormatEntry* pAutoFormatEntry, + PropertyType ePropType ); + + /** Converts line formatting to the passed property set. */ + void convertFormatting( + PropertySet& rPropSet, + const ModelRef< Shape >& rxShapeProp, + sal_Int32 nSeriesIdx ); + +private: + LinePropertiesPtr mxAutoLine; /// Automatic line properties. + LinePropertyIds& mrLinePropIds; /// Property identifiers for border/line formatting. +}; + +// ---------------------------------------------------------------------------- + +class FillFormatter : public DetailFormatterBase +{ +public: + explicit FillFormatter( + ObjectFormatterData& rData, + const AutoFormatEntry* pAutoFormatEntry, + PropertyType ePropType ); + + /** Converts area formatting to the passed property set. */ + void convertFormatting( + PropertySet& rPropSet, + const ModelRef< Shape >& rxShapeProp, + const PictureOptionsModel* pPicOptions, + sal_Int32 nSeriesIdx ); + +private: + FillPropertiesPtr mxAutoFill; /// Automatic fill properties. + FillPropertyIds& mrFillPropIds; /// Property identifiers for fill formatting. +}; + +// ---------------------------------------------------------------------------- + +class EffectFormatter : public DetailFormatterBase +{ +public: + explicit EffectFormatter( + ObjectFormatterData& rData, + const AutoFormatEntry* pAutoFormatEntry, + PropertyType ePropType ); + + /** Converts effect formatting to the passed property set. */ + void convertFormatting( + PropertySet& rPropSet, + const ModelRef< Shape >& rxShapeProp, + sal_Int32 nSeriesIdx ); +}; + +// ---------------------------------------------------------------------------- + +class TextFormatter : public DetailFormatterBase +{ +public: + explicit TextFormatter( + ObjectFormatterData& rData, + const AutoTextEntry* pAutoTextEntry, + const ModelRef< TextBody >& rxGlobalTextProp ); + + /** Converts text formatting to the passed property set. */ + void convertFormatting( + PropertySet& rPropSet, + const TextCharacterProperties* pTextProps ); + /** Converts text formatting to the passed property set. */ + void convertFormatting( + PropertySet& rPropSet, + const ModelRef< TextBody >& rxTextProp ); + +private: + TextCharacterPropertiesPtr mxAutoText; /// Automatic text properties. +}; + +// ---------------------------------------------------------------------------- + +/** Formatter for a specific object type. */ +class ObjectTypeFormatter +{ +public: + explicit ObjectTypeFormatter( + ObjectFormatterData& rData, + const ObjectTypeFormatEntry& rEntry, + const ChartSpaceModel& rChartSpace ); + + /** Sets frame formatting properties to the passed property set. */ + void convertFrameFormatting( + PropertySet& rPropSet, + const ModelRef< Shape >& rxShapeProp, + const PictureOptionsModel* pPicOptions, + sal_Int32 nSeriesIdx ); + + /** Sets text formatting properties to the passed property set. */ + void convertTextFormatting( + PropertySet& rPropSet, + const ModelRef< TextBody >& rxTextProp ); + + /** Sets frame/text formatting properties to the passed property set. */ + void convertFormatting( + PropertySet& rPropSet, + const ModelRef< Shape >& rxShapeProp, + const ModelRef< TextBody >& rxTextProp ); + + /** Sets text formatting properties to the passed property set. */ + void convertTextFormatting( + PropertySet& rPropSet, + const TextCharacterProperties& rTextProps ); + + /** Sets automatic line properties to the passed property set. */ + void convertAutomaticLine( + PropertySet& rPropSet, + sal_Int32 nSeriesIdx ); + + /** Sets automatic fill properties to the passed property set. */ + void convertAutomaticFill( + PropertySet& rPropSet, + sal_Int32 nSeriesIdx ); + +private: + LineFormatter maLineFormatter; /// Converter for line formatting. + FillFormatter maFillFormatter; /// Converter for fill formatting. + EffectFormatter maEffectFormatter; /// Converter for effect formatting. + TextFormatter maTextFormatter; /// Converter for text formatting. + const ObjectTypeFormatEntry& mrEntry; /// Additional settings. +}; + +// ---------------------------------------------------------------------------- + +struct ObjectFormatterData +{ + typedef RefMap< ObjectType, ObjectTypeFormatter > ObjectTypeFormatterMap; + + const XmlFilterBase& mrFilter; /// Base filter object. + ObjectTypeFormatterMap maTypeFormatters; /// Formatters for all types of objects in a chart. + ModelObjectHelper maModelObjHelper; /// Helper for named drawing formatting (dashes, gradients, bitmaps). + LinePropertyIds maCommonLineIds; /// Property identifiers for common border formatting. + LinePropertyIds maLinearLineIds; /// Property identifiers for line formatting of linear series. + LinePropertyIds maFilledLineIds; /// Property identifiers for line formatting of filled series. + FillPropertyIds maCommonFillIds; /// Property identifiers for common area fill. + FillPropertyIds maFilledFillIds; /// Property identifiers for area fill of filled series. + Reference< XNumberFormats > mxNumFmts; /// Number formats collection of container document. + Reference< XNumberFormatTypes > mxNumTypes; /// Number format types collection of container document. + Locale maEnUsLocale; /// Locale struct containing en-US. + Locale maFromLocale; /// Empty locale struct. + sal_Int32 mnMaxSeriesIdx; /// Maximum series index used for color cycling/fading. + + explicit ObjectFormatterData( + const XmlFilterBase& rFilter, + const Reference< XChartDocument >& rxChartDoc, + const ChartSpaceModel& rChartSpace ); + + ObjectTypeFormatter* getTypeFormatter( ObjectType eObjType ); + + LinePropertyIds& getLinePropertyIds( PropertyType ePropType ); + FillPropertyIds& getFillPropertyIds( PropertyType ePropType ); +}; + +// ============================================================================ + +DetailFormatterBase::DetailFormatterBase( ObjectFormatterData& rData, const AutoFormatEntry* pAutoFormatEntry ) : + mrData( rData ), + mnPhClr( -1 ) +{ + if( pAutoFormatEntry ) + { + if( pAutoFormatEntry->mpPattern ) + { + // prepare multi-color pattern + for( const AutoFormatPatternEntry* pPatternEntry = pAutoFormatEntry->mpPattern; pPatternEntry->mnColorToken != XML_TOKEN_INVALID; ++pPatternEntry ) + maColorPattern.push_back( getSchemeColor( pPatternEntry->mnColorToken, pPatternEntry->mnModToken, pPatternEntry->mnModValue ) ); + } + else if( pAutoFormatEntry->mnColorToken != XML_TOKEN_INVALID ) + { + // prepare color or single-color pattern (color fading) + mnPhClr = getSchemeColor( pAutoFormatEntry->mnColorToken, pAutoFormatEntry->mnModToken, pAutoFormatEntry->mnModValue ); + if( pAutoFormatEntry->mbFadedColor ) + maColorPattern.push_back( mnPhClr ); + } + } +} + +DetailFormatterBase::DetailFormatterBase( ObjectFormatterData& rData, const AutoTextEntry* pAutoTextEntry ) : + mrData( rData ), + mnPhClr( -1 ) +{ + if( pAutoTextEntry && (pAutoTextEntry->mnColorToken != XML_TOKEN_INVALID) ) + mnPhClr = getSchemeColor( pAutoTextEntry->mnColorToken, XML_TOKEN_INVALID, 0 ); +} + +sal_Int32 DetailFormatterBase::getPhColor( sal_Int32 nSeriesIdx ) const +{ + if( maColorPattern.empty() || (mrData.mnMaxSeriesIdx < 0) || (nSeriesIdx < 0) ) + return mnPhClr; + + /* Apply tint/shade depending on the cycle index. The colors of leading + series are darkened (color shade), the colors of trailing series are + lightened (color tint). Shade/tint is applied in an exclusive range of + -70% to 70%. + + Example 1: 3 data series using single-color shading with accent color 1 + (e.g. automatic chart style #3). Shade/tint is applied per series. + Shade/tint changes in steps of 140%/(<series_count+1) = 140%/4 = 35%, + starting at -70%: + Step 1: -70% -> Not used. + Step 2: -35% -> Series 1 has 35% shade of accent color 1. + Step 3: 0% -> Series 2 has pure accent color 1. + Step 4: 35% -> Series 3 has 35% tint of accent color 1. + Step 5: 70% -> Not used. + + Example 2: 20 data series using accent color pattern (e.g. automatic + chart style #2). Each color cycle has a size of 6 series (accent colors + 1 to 6). Shade/tint is applied per color cycle. + Cycle #1: Series 1...6 are based on accent colors 1 to 6. + Cycle #2: Series 7...12 are based on accent colors 1 to 6. + Cycle #3: Series 13...18 are based on accent colors 1 to 6. + Cycle #4: Series 19...20 are based on accent colors 1 to 2. + Shade/tint changes in steps of 140%/(cycle_count+1) = 140%/5 = 28%, + starting at -70%: + Step 1: -70% -> Not used. + Step 2: -42% -> Cycle #1 has 42% shade of accent colors 1...6 + step 3: -14% -> Cycle #2 has 14% shade of accent colors 1...6 + step 4: 14% -> Cycle #3 has 14% tint of accent colors 1...6 + step 5: 42% -> Cycle #4 has 42% tint of accent colors 1...6 + step 6: 70% -> Not used. + */ + sal_Int32 nPhClr = maColorPattern[ static_cast< size_t >( nSeriesIdx % maColorPattern.size() ) ]; + size_t nCycleIdx = static_cast< size_t >( nSeriesIdx / maColorPattern.size() ); + size_t nMaxCycleIdx = static_cast< size_t >( mrData.mnMaxSeriesIdx / maColorPattern.size() ); + double fShadeTint = static_cast< double >( nCycleIdx + 1 ) / (nMaxCycleIdx + 2) * 1.4 - 0.7; + if( fShadeTint != 0.0 ) + { + Color aColor; + aColor.setSrgbClr( nPhClr ); + aColor.addChartTintTransformation( fShadeTint ); + nPhClr = aColor.getColor( mrData.mrFilter.getGraphicHelper() ); + } + + return nPhClr; +} + +sal_Int32 DetailFormatterBase::getSchemeColor( sal_Int32 nColorToken, sal_Int32 nModToken, sal_Int32 nModValue ) const +{ + Color aColor; + aColor.setSchemeClr( nColorToken ); + if( nModToken != XML_TOKEN_INVALID ) + aColor.addTransformation( nModToken, nModValue ); + return aColor.getColor( mrData.mrFilter.getGraphicHelper() ); +} + +// ============================================================================ + +LineFormatter::LineFormatter( ObjectFormatterData& rData, const AutoFormatEntry* pAutoFormatEntry, PropertyType ePropType ) : + DetailFormatterBase( rData, pAutoFormatEntry ), + mrLinePropIds( rData.getLinePropertyIds( ePropType ) ) +{ + if( pAutoFormatEntry ) + { + mxAutoLine.reset( new LineProperties ); + mxAutoLine->maLineFill.moFillType = XML_noFill; + if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) + if( const LineProperties* pLineProps = pTheme->getLineStyle( pAutoFormatEntry->mnThemedIdx ) ) + *mxAutoLine = *pLineProps; + // change line width according to chart auto style + if( mxAutoLine->moLineWidth.has() ) + mxAutoLine->moLineWidth = mxAutoLine->moLineWidth.get() * pAutoFormatEntry->mnRelLineWidth / 100; + } +} + +void LineFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, sal_Int32 nSeriesIdx ) +{ + LineProperties aLineProps; + if( mxAutoLine.get() ) + aLineProps.assignUsed( *mxAutoLine ); + if( rxShapeProp.is() ) + aLineProps.assignUsed( rxShapeProp->getLineProperties() ); + aLineProps.pushToPropSet( rPropSet, mrData.maModelObjHelper, mrData.mrFilter.getGraphicHelper(), mrLinePropIds, getPhColor( nSeriesIdx ) ); +} + +// ============================================================================ + +FillFormatter::FillFormatter( ObjectFormatterData& rData, const AutoFormatEntry* pAutoFormatEntry, PropertyType ePropType ) : + DetailFormatterBase( rData, pAutoFormatEntry ), + mrFillPropIds( rData.getFillPropertyIds( ePropType ) ) +{ + if( pAutoFormatEntry ) + { + mxAutoFill.reset( new FillProperties ); + mxAutoFill->moFillType = XML_noFill; + if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) + if( const FillProperties* pFillProps = pTheme->getFillStyle( pAutoFormatEntry->mnThemedIdx ) ) + *mxAutoFill = *pFillProps; + } +} + +void FillFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, const PictureOptionsModel* pPicOptions, sal_Int32 nSeriesIdx ) +{ + FillProperties aFillProps; + if( mxAutoFill.get() ) + aFillProps.assignUsed( *mxAutoFill ); + if( rxShapeProp.is() ) + aFillProps.assignUsed( rxShapeProp->getFillProperties() ); + if( pPicOptions ) + lclConvertPictureOptions( aFillProps, *pPicOptions ); + aFillProps.pushToPropSet( rPropSet, mrData.maModelObjHelper, mrData.mrFilter.getGraphicHelper(), mrFillPropIds, 0, getPhColor( nSeriesIdx ) ); +} + +// ============================================================================ + +EffectFormatter::EffectFormatter( ObjectFormatterData& rData, const AutoFormatEntry* pAutoFormatEntry, PropertyType /*ePropType*/ ) : + DetailFormatterBase( rData, pAutoFormatEntry ) +{ +} + +void EffectFormatter::convertFormatting( PropertySet& /*rPropSet*/, const ModelRef< Shape >& /*rxShapeProp*/, sal_Int32 /*nSeriesIdx*/ ) +{ +} + +// ============================================================================ + +namespace { + +const TextCharacterProperties* lclGetTextProperties( const ModelRef< TextBody >& rxTextProp ) +{ + return (rxTextProp.is() && !rxTextProp->getParagraphs().empty()) ? + &rxTextProp->getParagraphs().front()->getProperties().getTextCharacterProperties() : 0; +} + +} // namespace + +TextFormatter::TextFormatter( ObjectFormatterData& rData, const AutoTextEntry* pAutoTextEntry, const ModelRef< TextBody >& rxGlobalTextProp ) : + DetailFormatterBase( rData, pAutoTextEntry ) +{ + if( pAutoTextEntry ) + { + mxAutoText.reset( new TextCharacterProperties ); + if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) + if( const TextCharacterProperties* pTextProps = pTheme->getFontStyle( pAutoTextEntry->mnThemedFont ) ) + *mxAutoText = *pTextProps; + sal_Int32 nTextColor = getPhColor( -1 ); + if( nTextColor >= 0 ) + mxAutoText->maCharColor.setSrgbClr( nTextColor ); + mxAutoText->moHeight = pAutoTextEntry->mnDefFontSize; + mxAutoText->moBold = pAutoTextEntry->mbBold; + + if( const TextCharacterProperties* pTextProps = lclGetTextProperties( rxGlobalTextProp ) ) + { + mxAutoText->assignUsed( *pTextProps ); + if( pTextProps->moHeight.has() ) + mxAutoText->moHeight = pTextProps->moHeight.get() * pAutoTextEntry->mnRelFontSize / 100; + } + } +} + +void TextFormatter::convertFormatting( PropertySet& rPropSet, const TextCharacterProperties* pTextProps ) +{ + TextCharacterProperties aTextProps; + if( mxAutoText.get() ) + aTextProps.assignUsed( *mxAutoText ); + if( pTextProps ) + aTextProps.assignUsed( *pTextProps ); + aTextProps.pushToPropSet( rPropSet, mrData.mrFilter ); +} + +void TextFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< TextBody >& rxTextProp ) +{ + convertFormatting( rPropSet, lclGetTextProperties( rxTextProp ) ); +} + +// ============================================================================ + +ObjectTypeFormatter::ObjectTypeFormatter( ObjectFormatterData& rData, const ObjectTypeFormatEntry& rEntry, const ChartSpaceModel& rChartSpace ) : + maLineFormatter( rData, lclGetAutoFormatEntry( rEntry.mpAutoLines, rChartSpace.mnStyle ), rEntry.mePropType ), + maFillFormatter( rData, lclGetAutoFormatEntry( rEntry.mpAutoFills, rChartSpace.mnStyle ), rEntry.mePropType ), + maEffectFormatter( rData, lclGetAutoFormatEntry( rEntry.mpAutoEffects, rChartSpace.mnStyle ), rEntry.mePropType ), + maTextFormatter( rData, lclGetAutoTextEntry( rEntry.mpAutoTexts, rChartSpace.mnStyle ), rChartSpace.mxTextProp ), + mrEntry( rEntry ) +{ +} + +void ObjectTypeFormatter::convertFrameFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, const PictureOptionsModel* pPicOptions, sal_Int32 nSeriesIdx ) +{ + maLineFormatter.convertFormatting( rPropSet, rxShapeProp, nSeriesIdx ); + if( mrEntry.mbIsFrame ) + maFillFormatter.convertFormatting( rPropSet, rxShapeProp, pPicOptions, nSeriesIdx ); + maEffectFormatter.convertFormatting( rPropSet, rxShapeProp, nSeriesIdx ); +} + +void ObjectTypeFormatter::convertTextFormatting( PropertySet& rPropSet, const ModelRef< TextBody >& rxTextProp ) +{ + maTextFormatter.convertFormatting( rPropSet, rxTextProp ); +} + +void ObjectTypeFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, const ModelRef< TextBody >& rxTextProp ) +{ + convertFrameFormatting( rPropSet, rxShapeProp, 0, -1 ); + convertTextFormatting( rPropSet, rxTextProp ); +} + +void ObjectTypeFormatter::convertTextFormatting( PropertySet& rPropSet, const TextCharacterProperties& rTextProps ) +{ + maTextFormatter.convertFormatting( rPropSet, &rTextProps ); +} + +void ObjectTypeFormatter::convertAutomaticLine( PropertySet& rPropSet, sal_Int32 nSeriesIdx ) +{ + ModelRef< Shape > xShapeProp; + maLineFormatter.convertFormatting( rPropSet, xShapeProp, nSeriesIdx ); + maEffectFormatter.convertFormatting( rPropSet, xShapeProp, nSeriesIdx ); +} + +void ObjectTypeFormatter::convertAutomaticFill( PropertySet& rPropSet, sal_Int32 nSeriesIdx ) +{ + ModelRef< Shape > xShapeProp; + maFillFormatter.convertFormatting( rPropSet, xShapeProp, 0, nSeriesIdx ); + maEffectFormatter.convertFormatting( rPropSet, xShapeProp, nSeriesIdx ); +} + +// ============================================================================ + +ObjectFormatterData::ObjectFormatterData( const XmlFilterBase& rFilter, const Reference< XChartDocument >& rxChartDoc, const ChartSpaceModel& rChartSpace ) : + mrFilter( rFilter ), + maModelObjHelper( Reference< XMultiServiceFactory >( rxChartDoc, UNO_QUERY ) ), + maCommonLineIds( spnCommonLineIds, true, false ), + maLinearLineIds( spnLinearLineIds, true, false ), + maFilledLineIds( spnFilledLineIds, true, false ), + maCommonFillIds( spnCommonFillIds, true, true ), + maFilledFillIds( spnFilledFillIds, true, true ), + maEnUsLocale( CREATE_OUSTRING( "en" ), CREATE_OUSTRING( "US" ), OUString() ), + mnMaxSeriesIdx( -1 ) +{ + const ObjectTypeFormatEntry* pEntryEnd = STATIC_ARRAY_END( spObjTypeFormatEntries ); + for( const ObjectTypeFormatEntry* pEntry = spObjTypeFormatEntries; pEntry != pEntryEnd; ++pEntry ) + maTypeFormatters[ pEntry->meObjType ].reset( new ObjectTypeFormatter( *this, *pEntry, rChartSpace ) ); + + try + { + Reference< XNumberFormatsSupplier > xNumFmtsSupp( mrFilter.getModel(), UNO_QUERY_THROW ); + mxNumFmts = xNumFmtsSupp->getNumberFormats(); + mxNumTypes.set( mxNumFmts, UNO_QUERY ); + } + catch( Exception& ) + { + } + OSL_ENSURE( mxNumFmts.is() && mxNumTypes.is(), "ObjectFormatterData::ObjectFormatterData - cannot get number formats" ); +} + +ObjectTypeFormatter* ObjectFormatterData::getTypeFormatter( ObjectType eObjType ) +{ + OSL_ENSURE( maTypeFormatters.has( eObjType ), "ObjectFormatterData::getTypeFormatter - unknown object type" ); + return maTypeFormatters.get( eObjType ).get(); +} + +LinePropertyIds& ObjectFormatterData::getLinePropertyIds( PropertyType ePropType ) +{ + switch( ePropType ) + { + case PROPERTYTYPE_COMMON: return maCommonLineIds; + case PROPERTYTYPE_LINEARSERIES: return maLinearLineIds; + case PROPERTYTYPE_FILLEDSERIES: return maFilledLineIds; + } + return maCommonLineIds; +} + +FillPropertyIds& ObjectFormatterData::getFillPropertyIds( PropertyType ePropType ) +{ + switch( ePropType ) + { + case PROPERTYTYPE_COMMON: return maCommonFillIds; + case PROPERTYTYPE_LINEARSERIES: return maCommonFillIds; + case PROPERTYTYPE_FILLEDSERIES: return maFilledFillIds; + } + return maCommonFillIds; +} + +// ============================================================================ + +ObjectFormatter::ObjectFormatter( const XmlFilterBase& rFilter, const Reference< XChartDocument >& rxChartDoc, const ChartSpaceModel& rChartSpace ) : + mxData( new ObjectFormatterData( rFilter, rxChartDoc, rChartSpace ) ) +{ +} + +ObjectFormatter::~ObjectFormatter() +{ +} + +void ObjectFormatter::setMaxSeriesIndex( sal_Int32 nMaxSeriesIdx ) +{ + mxData->mnMaxSeriesIdx = nMaxSeriesIdx; +} + +sal_Int32 ObjectFormatter::getMaxSeriesIndex() const +{ + return mxData->mnMaxSeriesIdx; +} + +void ObjectFormatter::convertFrameFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, ObjectType eObjType, sal_Int32 nSeriesIdx ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertFrameFormatting( rPropSet, rxShapeProp, 0, nSeriesIdx ); +} + +void ObjectFormatter::convertFrameFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, const PictureOptionsModel& rPicOptions, ObjectType eObjType, sal_Int32 nSeriesIdx ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertFrameFormatting( rPropSet, rxShapeProp, &rPicOptions, nSeriesIdx ); +} + +void ObjectFormatter::convertTextFormatting( PropertySet& rPropSet, const ModelRef< TextBody >& rxTextProp, ObjectType eObjType ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertTextFormatting( rPropSet, rxTextProp ); +} + +void ObjectFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< Shape >& rxShapeProp, const ModelRef< TextBody >& rxTextProp, ObjectType eObjType ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertFormatting( rPropSet, rxShapeProp, rxTextProp ); +} + +void ObjectFormatter::convertTextFormatting( PropertySet& rPropSet, const TextCharacterProperties& rTextProps, ObjectType eObjType ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertTextFormatting( rPropSet, rTextProps ); +} + +void ObjectFormatter::convertTextRotation( PropertySet& rPropSet, const ModelRef< TextBody >& rxTextProp, bool bSupportsStacked ) +{ + if( rxTextProp.is() ) + { + bool bStacked = false; + if( bSupportsStacked ) + { + sal_Int32 nVert = rxTextProp->getTextProperties().moVert.get( XML_horz ); + bStacked = (nVert == XML_wordArtVert) || (nVert == XML_wordArtVertRtl); + rPropSet.setProperty( PROP_StackCharacters, bStacked ); + } + + /* Chart2 expects rotation angle as double value in range of [0,360). + OOXML counts clockwise, Chart2 counts counterclockwise. */ + double fAngle = static_cast< double >( bStacked ? 0 : rxTextProp->getTextProperties().moRotation.get( 0 ) ); + fAngle = getDoubleIntervalValue< double >( -fAngle / 60000.0, 0.0, 360.0 ); + rPropSet.setProperty( PROP_TextRotation, fAngle ); + } +} + +void ObjectFormatter::convertNumberFormat( PropertySet& rPropSet, const NumberFormat& rNumberFormat, bool bPercentFormat ) +{ + if( mxData->mxNumFmts.is() ) + { + sal_Int32 nPropId = bPercentFormat ? PROP_PercentageNumberFormat : PROP_NumberFormat; + if( rNumberFormat.mbSourceLinked || (rNumberFormat.maFormatCode.getLength() == 0) ) + { + rPropSet.setProperty( nPropId, Any() ); + } + else try + { + sal_Int32 nIndex = rNumberFormat.maFormatCode.equalsIgnoreAsciiCaseAscii( "general" ) ? + mxData->mxNumTypes->getStandardIndex( mxData->maFromLocale ) : + mxData->mxNumFmts->addNewConverted( rNumberFormat.maFormatCode, mxData->maEnUsLocale, mxData->maFromLocale ); + if( nIndex >= 0 ) + rPropSet.setProperty( nPropId, nIndex ); + } + catch( Exception& ) + { + OSL_ENSURE( false, + OStringBuffer( "ObjectFormatter::convertNumberFormat - cannot create number format '" ). + append( OUStringToOString( rNumberFormat.maFormatCode, osl_getThreadTextEncoding() ) ).append( '\'' ).getStr() ); + } + } +} + +void ObjectFormatter::convertAutomaticLine( PropertySet& rPropSet, ObjectType eObjType, sal_Int32 nSeriesIdx ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertAutomaticLine( rPropSet, nSeriesIdx ); +} + +void ObjectFormatter::convertAutomaticFill( PropertySet& rPropSet, ObjectType eObjType, sal_Int32 nSeriesIdx ) +{ + if( ObjectTypeFormatter* pFormat = mxData->getTypeFormatter( eObjType ) ) + pFormat->convertAutomaticFill( rPropSet, nSeriesIdx ); +} + +/*static*/ bool ObjectFormatter::isAutomaticLine( const ModelRef< Shape >& rxShapeProp ) +{ + return !rxShapeProp || !rxShapeProp->getLineProperties().maLineFill.moFillType.has(); +} + +/*static*/ bool ObjectFormatter::isAutomaticFill( const ModelRef< Shape >& rxShapeProp ) +{ + return !rxShapeProp || !rxShapeProp->getFillProperties().moFillType.has(); +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/plotareacontext.cxx b/oox/source/drawingml/chart/plotareacontext.cxx new file mode 100644 index 000000000000..4f8268f06d66 --- /dev/null +++ b/oox/source/drawingml/chart/plotareacontext.cxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/plotareacontext.hxx" +#include "oox/drawingml/shapepropertiescontext.hxx" +#include "oox/drawingml/chart/axiscontext.hxx" +#include "oox/drawingml/chart/plotareamodel.hxx" +#include "oox/drawingml/chart/seriescontext.hxx" +#include "oox/drawingml/chart/titlecontext.hxx" +#include "oox/drawingml/chart/typegroupcontext.hxx" + +using ::oox::core::ContextHandler2Helper; +using ::oox::core::ContextHandlerRef; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +View3DContext::View3DContext( ContextHandler2Helper& rParent, View3DModel& rModel ) : + ContextBase< View3DModel >( rParent, rModel ) +{ +} + +View3DContext::~View3DContext() +{ +} + +ContextHandlerRef View3DContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( view3D ): + switch( nElement ) + { + case C_TOKEN( depthPercent ): + mrModel.mnDepthPercent = rAttribs.getInteger( XML_val, 100 ); + return 0; + case C_TOKEN( hPercent ): + mrModel.monHeightPercent = rAttribs.getInteger( XML_val, 100 ); + return 0; + case C_TOKEN( perspective ): + mrModel.mnPerspective = rAttribs.getInteger( XML_val, 30 ); + return 0; + case C_TOKEN( rAngAx ): + // default is 'false', not 'true' as specified + mrModel.mbRightAngled = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( rotX ): + // default value dependent on chart type + mrModel.monRotationX = rAttribs.getInteger( XML_val ); + return 0; + case C_TOKEN( rotY ): + // default value dependent on chart type + mrModel.monRotationY = rAttribs.getInteger( XML_val ); + return 0; + } + break; + } + return 0; +} + +// ============================================================================ + +WallFloorContext::WallFloorContext( ContextHandler2Helper& rParent, WallFloorModel& rModel ) : + ContextBase< WallFloorModel >( rParent, rModel ) +{ +} + +WallFloorContext::~WallFloorContext() +{ +} + +ContextHandlerRef WallFloorContext::onCreateContext( sal_Int32 nElement, const AttributeList& ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( backWall ): + case C_TOKEN( floor ): + case C_TOKEN( sideWall ): + switch( nElement ) + { + case C_TOKEN( pictureOptions ): + return new PictureOptionsContext( *this, mrModel.mxPicOptions.create() ); + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +PlotAreaContext::PlotAreaContext( ContextHandler2Helper& rParent, PlotAreaModel& rModel ) : + ContextBase< PlotAreaModel >( rParent, rModel ) +{ +} + +PlotAreaContext::~PlotAreaContext() +{ +} + +ContextHandlerRef PlotAreaContext::onCreateContext( sal_Int32 nElement, const AttributeList& ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( plotArea ): + switch( nElement ) + { + case C_TOKEN( area3DChart ): + case C_TOKEN( areaChart ): + return new AreaTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( bar3DChart ): + case C_TOKEN( barChart ): + return new BarTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( bubbleChart ): + return new BubbleTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( line3DChart ): + case C_TOKEN( lineChart ): + case C_TOKEN( stockChart ): + return new LineTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( doughnutChart ): + case C_TOKEN( ofPieChart ): + case C_TOKEN( pie3DChart ): + case C_TOKEN( pieChart ): + return new PieTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( radarChart ): + return new RadarTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( scatterChart ): + return new ScatterTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + case C_TOKEN( surface3DChart ): + case C_TOKEN( surfaceChart ): + return new SurfaceTypeGroupContext( *this, mrModel.maTypeGroups.create( nElement ) ); + + case C_TOKEN( catAx ): + return new CatAxisContext( *this, mrModel.maAxes.create( nElement ) ); + case C_TOKEN( dateAx ): + return new DateAxisContext( *this, mrModel.maAxes.create( nElement ) ); + case C_TOKEN( serAx ): + return new SerAxisContext( *this, mrModel.maAxes.create( nElement ) ); + case C_TOKEN( valAx ): + return new ValAxisContext( *this, mrModel.maAxes.create( nElement ) ); + + case C_TOKEN( layout ): + return new LayoutContext( *this, mrModel.mxLayout.create() ); + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/plotareaconverter.cxx b/oox/source/drawingml/chart/plotareaconverter.cxx new file mode 100644 index 000000000000..c3f74899ed97 --- /dev/null +++ b/oox/source/drawingml/chart/plotareaconverter.cxx @@ -0,0 +1,455 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/plotareaconverter.hxx" +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/chart/XDiagramPositioning.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XDiagram.hpp> +#include "oox/drawingml/chart/axisconverter.hxx" +#include "oox/drawingml/chart/plotareamodel.hxx" +#include "oox/drawingml/chart/typegroupconverter.hxx" +#include "properties.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::awt::Rectangle; +using ::com::sun::star::chart2::XCoordinateSystem; +using ::com::sun::star::chart2::XCoordinateSystemContainer; +using ::com::sun::star::chart2::XDiagram; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +/** Axes set model. This is a helper for the plot area converter collecting all + type groups and axes of the primary or secondary axes set. */ +struct AxesSetModel +{ + typedef ModelVector< TypeGroupModel > TypeGroupVector; + typedef ModelMap< sal_Int32, AxisModel > AxisMap; + + TypeGroupVector maTypeGroups; /// All type groups containing data series. + AxisMap maAxes; /// All axes mapped by API axis type. + + inline explicit AxesSetModel() {} + inline ~AxesSetModel() {} +}; + +// ============================================================================ + +/** Axes set converter. This is a helper class for the plot area converter. */ +class AxesSetConverter : public ConverterBase< AxesSetModel > +{ +public: + explicit AxesSetConverter( const ConverterRoot& rParent, AxesSetModel& rModel ); + virtual ~AxesSetConverter(); + + /** Converts the axes set model to a chart2 diagram. Returns an automatic + chart title from a single series title, if possible. */ + void convertFromModel( + const Reference< XDiagram >& rxDiagram, + View3DModel& rView3DModel, + sal_Int32 nAxesSetIdx, + bool bSupportsVaryColorsByPoint ); + + /** Returns the automatic chart title if the axes set contains only one series. */ + inline const ::rtl::OUString& getAutomaticTitle() const { return maAutoTitle; } + /** Returns true, if the chart is three-dimensional. */ + inline bool is3dChart() const { return mb3dChart; } + /** Returns true, if chart type supports wall and floor format in 3D mode. */ + inline bool isWall3dChart() const { return mbWall3dChart; } + /** Returns true, if chart is a pie chart or doughnut chart. */ + inline bool isPieChart() const { return mbPieChart; } + +private: + ::rtl::OUString maAutoTitle; + bool mb3dChart; + bool mbWall3dChart; + bool mbPieChart; +}; + +// ---------------------------------------------------------------------------- + +AxesSetConverter::AxesSetConverter( const ConverterRoot& rParent, AxesSetModel& rModel ) : + ConverterBase< AxesSetModel >( rParent, rModel ), + mb3dChart( false ), + mbWall3dChart( false ), + mbPieChart( false ) +{ +} + +AxesSetConverter::~AxesSetConverter() +{ +} + +ModelRef< AxisModel > lclGetOrCreateAxis( const AxesSetModel::AxisMap& rFromAxes, sal_Int32 nAxisIdx, sal_Int32 nDefTypeId ) +{ + ModelRef< AxisModel > xAxis = rFromAxes.get( nAxisIdx ); + if( !xAxis ) + xAxis.create( nDefTypeId ).mbDeleted = true; // missing axis is invisible + return xAxis; +} + +void AxesSetConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, + View3DModel& rView3DModel, sal_Int32 nAxesSetIdx, bool bSupportsVaryColorsByPoint ) +{ + // create type group converter objects for all type groups + typedef RefVector< TypeGroupConverter > TypeGroupConvVector; + TypeGroupConvVector aTypeGroups; + for( AxesSetModel::TypeGroupVector::iterator aIt = mrModel.maTypeGroups.begin(), aEnd = mrModel.maTypeGroups.end(); aIt != aEnd; ++aIt ) + aTypeGroups.push_back( TypeGroupConvVector::value_type( new TypeGroupConverter( *this, **aIt ) ) ); + + OSL_ENSURE( !aTypeGroups.empty(), "AxesSetConverter::convertFromModel - no type groups in axes set" ); + if( !aTypeGroups.empty() ) try + { + // first type group needed for coordinate system and axis conversion + TypeGroupConverter& rFirstTypeGroup = *aTypeGroups.front(); + + // get automatic chart title, if there is only one type group + if( aTypeGroups.size() == 1 ) + maAutoTitle = rFirstTypeGroup.getSingleSeriesTitle(); + + /* Create a coordinate system. For now, all type groups from all axes sets + have to be inserted into one coordinate system. Later, chart2 should + support using one coordinate system for each axes set. */ + Reference< XCoordinateSystem > xCoordSystem; + Reference< XCoordinateSystemContainer > xCoordSystemCont( rxDiagram, UNO_QUERY_THROW ); + Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems(); + if( aCoordSystems.hasElements() ) + { + OSL_ENSURE( aCoordSystems.getLength() == 1, "AxesSetConverter::convertFromModel - too many coordinate systems" ); + xCoordSystem = aCoordSystems[ 0 ]; + OSL_ENSURE( xCoordSystem.is(), "AxesSetConverter::convertFromModel - invalid coordinate system" ); + } + else + { + xCoordSystem = rFirstTypeGroup.createCoordinateSystem(); + if( xCoordSystem.is() ) + xCoordSystemCont->addCoordinateSystem( xCoordSystem ); + } + + // 3D view settings + mb3dChart = rFirstTypeGroup.is3dChart(); + mbWall3dChart = rFirstTypeGroup.isWall3dChart(); + mbPieChart = rFirstTypeGroup.getTypeInfo().meTypeCategory == TYPECATEGORY_PIE; + if( mb3dChart ) + { + View3DConverter aView3DConv( *this, rView3DModel ); + aView3DConv.convertFromModel( rxDiagram, rFirstTypeGroup ); + } + + /* Convert all chart type groups. Each type group will add its series + to the data provider attached to the chart document. */ + if( xCoordSystem.is() ) + { + // convert all axes (create missing axis models) + ModelRef< AxisModel > xXAxis = lclGetOrCreateAxis( mrModel.maAxes, API_X_AXIS, rFirstTypeGroup.getTypeInfo().mbCategoryAxis ? C_TOKEN( catAx ) : C_TOKEN( valAx ) ); + ModelRef< AxisModel > xYAxis = lclGetOrCreateAxis( mrModel.maAxes, API_Y_AXIS, C_TOKEN( valAx ) ); + + AxisConverter aXAxisConv( *this, *xXAxis ); + aXAxisConv.convertFromModel( xCoordSystem, rFirstTypeGroup, xYAxis.get(), nAxesSetIdx, API_X_AXIS ); + AxisConverter aYAxisConv( *this, *xYAxis ); + aYAxisConv.convertFromModel( xCoordSystem, rFirstTypeGroup, xXAxis.get(), nAxesSetIdx, API_Y_AXIS ); + + if( rFirstTypeGroup.isDeep3dChart() ) + { + ModelRef< AxisModel > xZAxis = lclGetOrCreateAxis( mrModel.maAxes, API_Z_AXIS, C_TOKEN( serAx ) ); + AxisConverter aZAxisConv( *this, *xZAxis ); + aZAxisConv.convertFromModel( xCoordSystem, rFirstTypeGroup, 0, nAxesSetIdx, API_Z_AXIS ); + } + + // convert all chart type groups, this converts all series data and formatting + for( TypeGroupConvVector::iterator aTIt = aTypeGroups.begin(), aTEnd = aTypeGroups.end(); aTIt != aTEnd; ++aTIt ) + (*aTIt)->convertFromModel( rxDiagram, xCoordSystem, nAxesSetIdx, bSupportsVaryColorsByPoint ); + } + } + catch( Exception& ) + { + } +} + +} // namespace + +// ============================================================================ + +View3DConverter::View3DConverter( const ConverterRoot& rParent, View3DModel& rModel ) : + ConverterBase< View3DModel >( rParent, rModel ) +{ +} + +View3DConverter::~View3DConverter() +{ +} + +void View3DConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, TypeGroupConverter& rTypeGroup ) +{ + namespace cssd = ::com::sun::star::drawing; + PropertySet aPropSet( rxDiagram ); + + sal_Int32 nRotationY = 0; + sal_Int32 nRotationX = 0; + bool bRightAngled = false; + sal_Int32 nAmbientColor = 0; + sal_Int32 nLightColor = 0; + + if( rTypeGroup.getTypeInfo().meTypeCategory == TYPECATEGORY_PIE ) + { + // Y rotation used as 'first pie slice angle' in 3D pie charts + rTypeGroup.convertPieRotation( aPropSet, mrModel.monRotationY.get( 0 ) ); + // X rotation a.k.a. elevation (map OOXML [0..90] to Chart2 [-90,0]) + nRotationX = getLimitedValue< sal_Int32, sal_Int32 >( mrModel.monRotationX.get( 15 ), 0, 90 ) - 90; + // no right-angled axes in pie charts + bRightAngled = false; + // ambient color (Gray 30%) + nAmbientColor = 0xB3B3B3; + // light color (Gray 70%) + nLightColor = 0x4C4C4C; + } + else // 3D bar/area/line charts + { + // Y rotation (OOXML [0..359], Chart2 [-179,180]) + nRotationY = mrModel.monRotationY.get( 20 ); + // X rotation a.k.a. elevation (OOXML [-90..90], Chart2 [-179,180]) + nRotationX = getLimitedValue< sal_Int32, sal_Int32 >( mrModel.monRotationX.get( 15 ), -90, 90 ); + // right-angled axes + bRightAngled = mrModel.mbRightAngled; + // ambient color (Gray 20%) + nAmbientColor = 0xCCCCCC; + // light color (Gray 60%) + nLightColor = 0x666666; + } + + // Y rotation (map OOXML [0..359] to Chart2 [-179,180]) + nRotationY %= 360; + if( nRotationY > 180 ) nRotationY -= 360; + /* Perspective (map OOXML [0..200] to Chart2 [0,100]). Seems that MSO 2007 is + buggy here, the XML plugin of MSO 2003 writes the correct perspective in + the range from 0 to 100. We will emulate the wrong behaviour of MSO 2007. */ + sal_Int32 nPerspective = getLimitedValue< sal_Int32, sal_Int32 >( mrModel.mnPerspective / 2, 0, 100 ); + // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%) + bool bParallel = bRightAngled || (nPerspective == 0); + cssd::ProjectionMode eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE; + + // set rotation properties + aPropSet.setProperty( PROP_RotationVertical, nRotationY ); + aPropSet.setProperty( PROP_RotationHorizontal, nRotationX ); + aPropSet.setProperty( PROP_Perspective, nPerspective ); + aPropSet.setProperty( PROP_RightAngledAxes, bRightAngled ); + aPropSet.setProperty( PROP_D3DScenePerspective, eProjMode ); + + // set light settings + aPropSet.setProperty( PROP_D3DSceneShadeMode, cssd::ShadeMode_FLAT ); + aPropSet.setProperty( PROP_D3DSceneAmbientColor, nAmbientColor ); + aPropSet.setProperty( PROP_D3DSceneLightOn1, false ); + aPropSet.setProperty( PROP_D3DSceneLightOn2, true ); + aPropSet.setProperty( PROP_D3DSceneLightColor2, nLightColor ); + aPropSet.setProperty( PROP_D3DSceneLightDirection2, cssd::Direction3D( 0.2, 0.4, 1.0 ) ); +} + +// ============================================================================ + +WallFloorConverter::WallFloorConverter( const ConverterRoot& rParent, WallFloorModel& rModel ) : + ConverterBase< WallFloorModel >( rParent, rModel ) +{ +} + +WallFloorConverter::~WallFloorConverter() +{ +} + +void WallFloorConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, ObjectType eObjType ) +{ + if( rxDiagram.is() ) + { + PropertySet aPropSet; + switch( eObjType ) + { + case OBJECTTYPE_FLOOR: aPropSet.set( rxDiagram->getFloor() ); break; + case OBJECTTYPE_WALL: aPropSet.set( rxDiagram->getWall() ); break; + default: OSL_ENSURE( false, "WallFloorConverter::convertFromModel - invalid object type" ); + } + if( aPropSet.is() ) + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(), eObjType ); + } +} + +// ============================================================================ + +PlotAreaConverter::PlotAreaConverter( const ConverterRoot& rParent, PlotAreaModel& rModel ) : + ConverterBase< PlotAreaModel >( rParent, rModel ), + mb3dChart( false ), + mbWall3dChart( false ), + mbPieChart( false ) +{ +} + +PlotAreaConverter::~PlotAreaConverter() +{ +} + +void PlotAreaConverter::convertFromModel( View3DModel& rView3DModel ) +{ + /* Create the diagram object and attach it to the chart document. One + diagram is used to carry all coordinate systems and data series. */ + Reference< XDiagram > xDiagram; + try + { + xDiagram.set( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.Diagram" ) ), UNO_QUERY_THROW ); + getChartDocument()->setFirstDiagram( xDiagram ); + } + catch( Exception& ) + { + } + + // store all axis models in a map, keyed by axis identifier + typedef ModelMap< sal_Int32, AxisModel > AxisMap; + AxisMap aAxisMap; + for( PlotAreaModel::AxisVector::iterator aAIt = mrModel.maAxes.begin(), aAEnd = mrModel.maAxes.end(); aAIt != aAEnd; ++aAIt ) + { + PlotAreaModel::AxisVector::value_type xAxis = *aAIt; + OSL_ENSURE( xAxis->mnAxisId >= 0, "PlotAreaConverter::convertFromModel - invalid axis identifier" ); + OSL_ENSURE( !aAxisMap.has( xAxis->mnAxisId ), "PlotAreaConverter::convertFromModel - axis identifiers not unique" ); + if( xAxis->mnAxisId >= 0 ) + aAxisMap[ xAxis->mnAxisId ] = xAxis; + } + + // group the type group models into different axes sets + typedef ModelVector< AxesSetModel > AxesSetVector; + AxesSetVector aAxesSets; + sal_Int32 nMaxSeriesIdx = -1; + for( PlotAreaModel::TypeGroupVector::iterator aTIt = mrModel.maTypeGroups.begin(), aTEnd = mrModel.maTypeGroups.end(); aTIt != aTEnd; ++aTIt ) + { + PlotAreaModel::TypeGroupVector::value_type xTypeGroup = *aTIt; + if( !xTypeGroup->maSeries.empty() ) + { + // try to find a compatible axes set for the type group + AxesSetModel* pAxesSet = 0; + for( AxesSetVector::iterator aASIt = aAxesSets.begin(), aASEnd = aAxesSets.end(); !pAxesSet && (aASIt != aASEnd); ++aASIt ) + if( (*aASIt)->maTypeGroups.front()->maAxisIds == xTypeGroup->maAxisIds ) + pAxesSet = aASIt->get(); + + // not possible to insert into an existing axes set -> start a new axes set + if( !pAxesSet ) + { + pAxesSet = &aAxesSets.create(); + // find axis models used by the type group + const TypeGroupModel::AxisIdVector& rAxisIds = xTypeGroup->maAxisIds; + if( rAxisIds.size() >= 1 ) + pAxesSet->maAxes[ API_X_AXIS ] = aAxisMap.get( rAxisIds[ 0 ] ); + if( rAxisIds.size() >= 2 ) + pAxesSet->maAxes[ API_Y_AXIS ] = aAxisMap.get( rAxisIds[ 1 ] ); + if( rAxisIds.size() >= 3 ) + pAxesSet->maAxes[ API_Z_AXIS ] = aAxisMap.get( rAxisIds[ 2 ] ); + } + + // insert the type group model + pAxesSet->maTypeGroups.push_back( xTypeGroup ); + + // collect the maximum series index for automatic series formatting + for( TypeGroupModel::SeriesVector::iterator aSIt = xTypeGroup->maSeries.begin(), aSEnd = xTypeGroup->maSeries.end(); aSIt != aSEnd; ++aSIt ) + nMaxSeriesIdx = ::std::max( nMaxSeriesIdx, (*aSIt)->mnIndex ); + } + } + getFormatter().setMaxSeriesIndex( nMaxSeriesIdx ); + + // varying point colors only for single series in single chart type + bool bSupportsVaryColorsByPoint = mrModel.maTypeGroups.size() == 1; + + // convert all axes sets + for( AxesSetVector::iterator aASBeg = aAxesSets.begin(), aASIt = aASBeg, aASEnd = aAxesSets.end(); aASIt != aASEnd; ++aASIt ) + { + AxesSetConverter aAxesSetConv( *this, **aASIt ); + sal_Int32 nAxesSetIdx = static_cast< sal_Int32 >( aASIt - aASBeg ); + aAxesSetConv.convertFromModel( xDiagram, rView3DModel, nAxesSetIdx, bSupportsVaryColorsByPoint ); + if( nAxesSetIdx == 0 ) + { + maAutoTitle = aAxesSetConv.getAutomaticTitle(); + mb3dChart = aAxesSetConv.is3dChart(); + mbWall3dChart = aAxesSetConv.isWall3dChart(); + mbPieChart = aAxesSetConv.isPieChart(); + } + else + { + maAutoTitle = OUString(); + } + } + + // plot area formatting + if( xDiagram.is() && !mb3dChart ) + { + PropertySet aPropSet( xDiagram->getWall() ); + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, OBJECTTYPE_PLOTAREA2D ); + } +} + +void PlotAreaConverter::convertPositionFromModel() +{ + LayoutModel& rLayout = mrModel.mxLayout.getOrCreate(); + LayoutConverter aLayoutConv( *this, rLayout ); + Rectangle aDiagramRect; + if( aLayoutConv.calcAbsRectangle( aDiagramRect ) ) try + { + namespace cssc = ::com::sun::star::chart; + Reference< cssc::XChartDocument > xChart1Doc( getChartDocument(), UNO_QUERY_THROW ); + Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW ); + // for pie charts, always set inner plot area size to exclude the data labels as Excel does + sal_Int32 nTarget = (mbPieChart && (rLayout.mnTarget == XML_outer)) ? XML_inner : rLayout.mnTarget; + switch( nTarget ) + { + case XML_inner: + xPositioning->setDiagramPositionExcludingAxes( aDiagramRect ); + break; + case XML_outer: + xPositioning->setDiagramPositionIncludingAxes( aDiagramRect ); + break; + default: + OSL_ENSURE( false, "PlotAreaConverter::convertPositionFromModel - unknown positioning target" ); + } + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/plotareamodel.cxx b/oox/source/drawingml/chart/plotareamodel.cxx new file mode 100644 index 000000000000..324186526cc6 --- /dev/null +++ b/oox/source/drawingml/chart/plotareamodel.cxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/plotareamodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +View3DModel::View3DModel() : + mnDepthPercent( 100 ), + mnPerspective( 30 ), + mbRightAngled( false ) +{ +} + +View3DModel::~View3DModel() +{ +} + +// ============================================================================ + +WallFloorModel::WallFloorModel() +{ +} + +WallFloorModel::~WallFloorModel() +{ +} + +// ============================================================================ + +PlotAreaModel::PlotAreaModel() +{ +} + +PlotAreaModel::~PlotAreaModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/seriescontext.cxx b/oox/source/drawingml/chart/seriescontext.cxx new file mode 100644 index 000000000000..d06ca9716944 --- /dev/null +++ b/oox/source/drawingml/chart/seriescontext.cxx @@ -0,0 +1,760 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/seriescontext.hxx" +#include "oox/drawingml/shapepropertiescontext.hxx" +#include "oox/drawingml/textbodycontext.hxx" +#include "oox/drawingml/chart/datasourcecontext.hxx" +#include "oox/drawingml/chart/seriesmodel.hxx" +#include "oox/drawingml/chart/titlecontext.hxx" + +using ::rtl::OUString; +using ::oox::core::ContextHandler2; +using ::oox::core::ContextHandler2Helper; +using ::oox::core::ContextHandlerRef; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +ContextHandlerRef lclDataLabelSharedCreateContext( + ContextHandler2& rContext, sal_Int32 nElement, const AttributeList& rAttribs, DataLabelModelBase& orModel ) +{ + if( rContext.isRootElement() ) switch( nElement ) + { + case C_TOKEN( delete ): + // default is 'false', not 'true' as specified + orModel.mbDeleted = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( dLblPos ): + orModel.monLabelPos = rAttribs.getToken( XML_val, XML_TOKEN_INVALID ); + return 0; + case C_TOKEN( numFmt ): + orModel.maNumberFormat.setAttributes( rAttribs ); + return 0; + case C_TOKEN( showBubbleSize ): + orModel.mobShowBubbleSize = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( showCatName ): + orModel.mobShowCatName = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( showLegendKey ): + orModel.mobShowLegendKey = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( showPercent ): + orModel.mobShowPercent = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( showSerName ): + orModel.mobShowSerName = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( showVal ): + orModel.mobShowVal = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( separator ): + // collect separator text in onEndElement() + return &rContext; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( rContext, orModel.mxShapeProp.create() ); + case C_TOKEN( txPr ): + return new TextBodyContext( rContext, orModel.mxTextProp.create() ); + } + return 0; +} + +void lclDataLabelSharedEndElement( ContextHandler2& rContext, const OUString& rChars, DataLabelModelBase& orModel ) +{ + switch( rContext.getCurrentElement() ) + { + case C_TOKEN( separator ): + orModel.moaSeparator = rChars; + break; + } +} + +} // namespace + +// ============================================================================ + +DataLabelContext::DataLabelContext( ContextHandler2Helper& rParent, DataLabelModel& rModel ) : + ContextBase< DataLabelModel >( rParent, rModel ) +{ +} + +DataLabelContext::~DataLabelContext() +{ +} + +ContextHandlerRef DataLabelContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( idx ): + mrModel.mnIndex = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( layout ): + return new LayoutContext( *this, mrModel.mxLayout.create() ); + case C_TOKEN( tx ): + return new TextContext( *this, mrModel.mxText.create() ); + } + return lclDataLabelSharedCreateContext( *this, nElement, rAttribs, mrModel ); +} + +void DataLabelContext::onEndElement( const OUString& rChars ) +{ + lclDataLabelSharedEndElement( *this, rChars, mrModel ); +} + +// ============================================================================ + +DataLabelsContext::DataLabelsContext( ContextHandler2Helper& rParent, DataLabelsModel& rModel ) : + ContextBase< DataLabelsModel >( rParent, rModel ) +{ +} + +DataLabelsContext::~DataLabelsContext() +{ +} + +ContextHandlerRef DataLabelsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( dLbl ): + return new DataLabelContext( *this, mrModel.maPointLabels.create() ); + case C_TOKEN( leaderLines ): + return new ShapePrWrapperContext( *this, mrModel.mxLeaderLines.create() ); + case C_TOKEN( showLeaderLines ): + // default is 'false', not 'true' as specified + mrModel.mbShowLeaderLines = rAttribs.getBool( XML_val, false ); + return 0; + } + return lclDataLabelSharedCreateContext( *this, nElement, rAttribs, mrModel ); +} + +void DataLabelsContext::onEndElement( const OUString& rChars ) +{ + lclDataLabelSharedEndElement( *this, rChars, mrModel ); +} + +// ============================================================================ + +PictureOptionsContext::PictureOptionsContext( ContextHandler2Helper& rParent, PictureOptionsModel& rModel ) : + ContextBase< PictureOptionsModel >( rParent, rModel ) +{ +} + +PictureOptionsContext::~PictureOptionsContext() +{ +} + +ContextHandlerRef PictureOptionsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( applyToEnd ): + // default is 'false', not 'true' as specified + mrModel.mbApplyToEnd = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( applyToFront ): + // default is 'false', not 'true' as specified + mrModel.mbApplyToFront = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( applyToSides ): + // default is 'false', not 'true' as specified + mrModel.mbApplyToSides = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( pictureFormat ): + mrModel.mnPictureFormat = rAttribs.getToken( XML_val, XML_stretch ); + return 0; + case C_TOKEN( pictureStackUnit ): + mrModel.mfStackUnit = rAttribs.getDouble( XML_val, 1.0 ); + return 0; + } + return 0; +} + +// ============================================================================ + +ErrorBarContext::ErrorBarContext( ContextHandler2Helper& rParent, ErrorBarModel& rModel ) : + ContextBase< ErrorBarModel >( rParent, rModel ) +{ +} + +ErrorBarContext::~ErrorBarContext() +{ +} + +ContextHandlerRef ErrorBarContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( errBarType ): + mrModel.mnTypeId = rAttribs.getToken( XML_val, XML_both ); + return 0; + case C_TOKEN( errDir ): + mrModel.mnDirection = rAttribs.getToken( XML_val, XML_TOKEN_INVALID ); + return 0; + case C_TOKEN( errValType ): + mrModel.mnValueType = rAttribs.getToken( XML_val, XML_fixedVal ); + return 0; + case C_TOKEN( minus ): + return new DataSourceContext( *this, mrModel.maSources.create( ErrorBarModel::MINUS ) ); + case C_TOKEN( noEndCap ): + // default is 'false', not 'true' as specified + mrModel.mbNoEndCap = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( plus ): + return new DataSourceContext( *this, mrModel.maSources.create( ErrorBarModel::PLUS ) ); + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( val ): + mrModel.mfValue = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + } + return 0; +} + +// ============================================================================ + +TrendlineLabelContext::TrendlineLabelContext( ContextHandler2Helper& rParent, TrendlineLabelModel& rModel ) : + ContextBase< TrendlineLabelModel >( rParent, rModel ) +{ +} + +TrendlineLabelContext::~TrendlineLabelContext() +{ +} + +ContextHandlerRef TrendlineLabelContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( layout ): + return new LayoutContext( *this, mrModel.mxLayout.create() ); + case C_TOKEN( numFmt ): + mrModel.maNumberFormat.setAttributes( rAttribs ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( tx ): + return new TextContext( *this, mrModel.mxText.create() ); + case C_TOKEN( txPr ): + return new TextBodyContext( *this, mrModel.mxTextProp.create() ); + } + return 0; +} + +// ============================================================================ + +TrendlineContext::TrendlineContext( ContextHandler2Helper& rParent, TrendlineModel& rModel ) : + ContextBase< TrendlineModel >( rParent, rModel ) +{ +} + +TrendlineContext::~TrendlineContext() +{ +} + +ContextHandlerRef TrendlineContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( backward ): + mrModel.mfBackward = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( dispEq ): + // default is 'false', not 'true' as specified + mrModel.mbDispEquation = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( dispRSqr ): + // default is 'false', not 'true' as specified + mrModel.mbDispRSquared = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( forward ): + mrModel.mfForward = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( intercept ): + mrModel.mfIntercept = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( name ): + return this; // collect name in onEndElement() + case C_TOKEN( order ): + mrModel.mnOrder = rAttribs.getInteger( XML_val, 2 ); + return 0; + case C_TOKEN( period ): + mrModel.mnPeriod = rAttribs.getInteger( XML_val, 2 ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( trendlineLbl ): + return new TrendlineLabelContext( *this, mrModel.mxLabel.create() ); + case C_TOKEN( trendlineType ): + mrModel.mnTypeId = rAttribs.getToken( XML_val, XML_linear ); + return 0; + } + return 0; +} + +void TrendlineContext::onEndElement( const ::rtl::OUString& rChars ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( name ): + mrModel.maName = rChars; + break; + } +} + +// ============================================================================ + +DataPointContext::DataPointContext( ContextHandler2Helper& rParent, DataPointModel& rModel ) : + ContextBase< DataPointModel >( rParent, rModel ) +{ +} + +DataPointContext::~DataPointContext() +{ +} + +ContextHandlerRef DataPointContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( dPt ): + switch( nElement ) + { + case C_TOKEN( bubble3D ): + mrModel.mobBubble3d = rAttribs.getBool( XML_val ); + return 0; + case C_TOKEN( explosion ): + // if the 'val' attribute is missing, series explosion remains unchanged + mrModel.monExplosion = rAttribs.getInteger( XML_val ); + return 0; + case C_TOKEN( idx ): + mrModel.mnIndex = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( invertIfNegative ): + // default is 'false', not 'true' as specified (value not derived from series!) + mrModel.mbInvertNeg = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( marker ): + return this; + case C_TOKEN( pictureOptions ): + return new PictureOptionsContext( *this, mrModel.mxPicOptions.create() ); + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + } + break; + + case C_TOKEN( marker ): + switch( nElement ) + { + case C_TOKEN( size ): + mrModel.monMarkerSize = rAttribs.getInteger( XML_val, 5 ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxMarkerProp.create() ); + case C_TOKEN( symbol ): + mrModel.monMarkerSymbol = rAttribs.getToken( XML_val, XML_none ); + return 0; + } + break; + } + return 0; +} + +// ============================================================================ + +SeriesContextBase::SeriesContextBase( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + ContextBase< SeriesModel >( rParent, rModel ) +{ +} + +SeriesContextBase::~SeriesContextBase() +{ +} + +ContextHandlerRef SeriesContextBase::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( idx ): + mrModel.mnIndex = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( order ): + mrModel.mnOrder = rAttribs.getInteger( XML_val, -1 ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( tx ): + return new TextContext( *this, mrModel.mxText.create() ); + } + break; + + case C_TOKEN( marker ): + switch( nElement ) + { + case C_TOKEN( size ): + mrModel.mnMarkerSize = rAttribs.getInteger( XML_val, 5 ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxMarkerProp.create() ); + case C_TOKEN( symbol ): + mrModel.mnMarkerSymbol = rAttribs.getToken( XML_val, XML_none ); + return 0; + } + break; + } + return 0; +} + +// ============================================================================ + +AreaSeriesContext::AreaSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +AreaSeriesContext::~AreaSeriesContext() +{ +} + +ContextHandlerRef AreaSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( cat ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( errBars ): + return new ErrorBarContext( *this, mrModel.maErrorBars.create() ); + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( trendline ): + return new TrendlineContext( *this, mrModel.maTrendlines.create() ); + case C_TOKEN( val ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +BarSeriesContext::BarSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +BarSeriesContext::~BarSeriesContext() +{ +} + +ContextHandlerRef BarSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( cat ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( errBars ): + return new ErrorBarContext( *this, mrModel.maErrorBars.create() ); + case C_TOKEN( invertIfNegative ): + // default is 'false', not 'true' as specified + mrModel.mbInvertNeg = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( pictureOptions ): + return new PictureOptionsContext( *this, mrModel.mxPicOptions.create() ); + case C_TOKEN( shape ): + // missing attribute does not change shape type to 'box' as specified + mrModel.monShape = rAttribs.getToken( XML_val ); + return 0; + case C_TOKEN( trendline ): + return new TrendlineContext( *this, mrModel.maTrendlines.create() ); + case C_TOKEN( val ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +BubbleSeriesContext::BubbleSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +BubbleSeriesContext::~BubbleSeriesContext() +{ +} + +ContextHandlerRef BubbleSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( bubble3D ): + // default is 'false', not 'true' as specified + mrModel.mbBubble3d = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( bubbleSize ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::POINTS ) ); + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( errBars ): + return new ErrorBarContext( *this, mrModel.maErrorBars.create() ); + case C_TOKEN( invertIfNegative ): + // default is 'false', not 'true' as specified + mrModel.mbInvertNeg = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( trendline ): + return new TrendlineContext( *this, mrModel.maTrendlines.create() ); + case C_TOKEN( xVal ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( yVal ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +LineSeriesContext::LineSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +LineSeriesContext::~LineSeriesContext() +{ +} + +ContextHandlerRef LineSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( cat ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( errBars ): + return new ErrorBarContext( *this, mrModel.maErrorBars.create() ); + case C_TOKEN( marker ): + return this; + case C_TOKEN( smooth ): + // default is 'false', not 'true' as specified + mrModel.mbSmooth = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( trendline ): + return new TrendlineContext( *this, mrModel.maTrendlines.create() ); + case C_TOKEN( val ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +PieSeriesContext::PieSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +PieSeriesContext::~PieSeriesContext() +{ +} + +ContextHandlerRef PieSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( cat ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( explosion ): + mrModel.mnExplosion = rAttribs.getInteger( XML_val, 0 ); + return 0; + case C_TOKEN( val ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +RadarSeriesContext::RadarSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +RadarSeriesContext::~RadarSeriesContext() +{ +} + +ContextHandlerRef RadarSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( cat ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( marker ): + return this; + case C_TOKEN( smooth ): + // default is 'false', not 'true' as specified + mrModel.mbSmooth = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( val ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +ScatterSeriesContext::ScatterSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +ScatterSeriesContext::~ScatterSeriesContext() +{ +} + +ContextHandlerRef ScatterSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dPt ): + return new DataPointContext( *this, mrModel.maPoints.create() ); + case C_TOKEN( errBars ): + return new ErrorBarContext( *this, mrModel.maErrorBars.create() ); + case C_TOKEN( marker ): + return this; + case C_TOKEN( smooth ): + // default is 'false', not 'true' as specified + mrModel.mbSmooth = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( trendline ): + return new TrendlineContext( *this, mrModel.maTrendlines.create() ); + case C_TOKEN( xVal ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( yVal ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +SurfaceSeriesContext::SurfaceSeriesContext( ContextHandler2Helper& rParent, SeriesModel& rModel ) : + SeriesContextBase( rParent, rModel ) +{ +} + +SurfaceSeriesContext::~SurfaceSeriesContext() +{ +} + +ContextHandlerRef SurfaceSeriesContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( ser ): + switch( nElement ) + { + case C_TOKEN( cat ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::CATEGORIES ) ); + case C_TOKEN( val ): + return new DataSourceContext( *this, mrModel.maSources.create( SeriesModel::VALUES ) ); + } + break; + } + return SeriesContextBase::onCreateContext( nElement, rAttribs ); +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/seriesconverter.cxx b/oox/source/drawingml/chart/seriesconverter.cxx new file mode 100644 index 000000000000..717a3972550e --- /dev/null +++ b/oox/source/drawingml/chart/seriesconverter.cxx @@ -0,0 +1,624 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/seriesconverter.hxx" +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart/ErrorBarStyle.hpp> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <com/sun/star/chart2/XRegressionCurve.hpp> +#include <com/sun/star/chart2/XRegressionCurveContainer.hpp> +#include <com/sun/star/chart2/data/XDataSink.hpp> +#include "oox/drawingml/chart/datasourceconverter.hxx" +#include "oox/drawingml/chart/seriesmodel.hxx" +#include "oox/drawingml/chart/titleconverter.hxx" +#include "oox/drawingml/chart/typegroupconverter.hxx" +#include "oox/drawingml/chart/typegroupmodel.hxx" +#include "properties.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::chart2::DataPointLabel; +using ::com::sun::star::chart2::XDataSeries; +using ::com::sun::star::chart2::XRegressionCurve; +using ::com::sun::star::chart2::XRegressionCurveContainer; +using ::com::sun::star::chart2::data::XDataSequence; +using ::com::sun::star::chart2::data::XDataSink; +using ::com::sun::star::chart2::data::XLabeledDataSequence; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +Reference< XLabeledDataSequence > lclCreateLabeledDataSequence( + const ConverterRoot& rParent, + DataSourceModel* pValues, const OUString& rRole, + TextModel* pTitle = 0 ) +{ + // create data sequence for values + Reference< XDataSequence > xValueSeq; + if( pValues ) + { + DataSourceConverter aSourceConv( rParent, *pValues ); + xValueSeq = aSourceConv.createDataSequence( rRole ); + } + + // create data sequence for title + Reference< XDataSequence > xTitleSeq; + if( pTitle ) + { + TextConverter aTextConv( rParent, *pTitle ); + xTitleSeq = aTextConv.createDataSequence( CREATE_OUSTRING( "label" ) ); + } + + // create the labeled data sequence, if values or title are present + Reference< XLabeledDataSequence > xLabeledSeq; + if( xValueSeq.is() || xTitleSeq.is() ) + { + xLabeledSeq.set( rParent.createInstance( CREATE_OUSTRING( "com.sun.star.chart2.data.LabeledDataSequence" ) ), UNO_QUERY ); + if( xLabeledSeq.is() ) + { + xLabeledSeq->setValues( xValueSeq ); + xLabeledSeq->setLabel( xTitleSeq ); + } + } + return xLabeledSeq; +} + +void lclConvertLabelFormatting( PropertySet& rPropSet, ObjectFormatter& rFormatter, + const DataLabelModelBase& rDataLabel, const TypeGroupConverter& rTypeGroup, bool bDataSeriesLabel ) +{ + const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo(); + + /* Excel 2007 does not change the series setting for a single data point, + if none of some specific elements occur. But only one existing element + in a data point will reset most other of these elements from the series + (e.g.: series has <c:showVal>, data point has <c:showCatName>, this + will reset <c:showVal> for this point, unless <c:showVal> is repeated + in the data point). The elements <c:layout>, <c:numberFormat>, + <c:spPr>, <c:tx>, and <c:txPr> are not affected at all. */ + bool bHasAnyElement = + rDataLabel.moaSeparator.has() || rDataLabel.monLabelPos.has() || + rDataLabel.mobShowCatName.has() || rDataLabel.mobShowLegendKey.has() || + rDataLabel.mobShowPercent.has() || rDataLabel.mobShowSerName.has() || + rDataLabel.mobShowVal.has(); + + bool bShowValue = !rDataLabel.mbDeleted && rDataLabel.mobShowVal.get( false ); + bool bShowPercent = !rDataLabel.mbDeleted && rDataLabel.mobShowPercent.get( false ) && (rTypeInfo.meTypeCategory == TYPECATEGORY_PIE); + bool bShowCateg = !rDataLabel.mbDeleted && rDataLabel.mobShowCatName.get( false ); + bool bShowSymbol = !rDataLabel.mbDeleted && rDataLabel.mobShowLegendKey.get( false ); + + // type of attached label + if( bHasAnyElement || rDataLabel.mbDeleted ) + { + DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol ); + rPropSet.setProperty( PROP_Label, aPointLabel ); + } + + if( !rDataLabel.mbDeleted ) + { + // data label number format (percentage format wins over value format) + rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, bShowPercent ); + + // data label text formatting (frame formatting not supported by Chart2) + rFormatter.convertTextFormatting( rPropSet, rDataLabel.mxTextProp, OBJECTTYPE_DATALABEL ); + rFormatter.convertTextRotation( rPropSet, rDataLabel.mxTextProp, false ); + + // data label separator (do not overwrite series separator, if no explicit point separator is present) + if( bDataSeriesLabel || rDataLabel.moaSeparator.has() ) + rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( CREATE_OUSTRING( "; " ) ) ); + + // data label placement (do not overwrite series placement, if no explicit point placement is present) + if( bDataSeriesLabel || rDataLabel.monLabelPos.has() ) + { + namespace csscd = ::com::sun::star::chart::DataLabelPlacement; + sal_Int32 nPlacement = rTypeInfo.mnDefLabelPos; + switch( rDataLabel.monLabelPos.get( XML_TOKEN_INVALID ) ) + { + case XML_outEnd: nPlacement = csscd::OUTSIDE; break; + case XML_inEnd: nPlacement = csscd::INSIDE; break; + case XML_ctr: nPlacement = csscd::CENTER; break; + case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break; + case XML_t: nPlacement = csscd::TOP; break; + case XML_b: nPlacement = csscd::BOTTOM; break; + case XML_l: nPlacement = csscd::LEFT; break; + case XML_r: nPlacement = csscd::RIGHT; break; + case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break; + } + rPropSet.setProperty( PROP_LabelPlacement, nPlacement ); + } + } +} + +} // namespace + +// ============================================================================ + +DataLabelConverter::DataLabelConverter( const ConverterRoot& rParent, DataLabelModel& rModel ) : + ConverterBase< DataLabelModel >( rParent, rModel ) +{ +} + +DataLabelConverter::~DataLabelConverter() +{ +} + +void DataLabelConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup ) +{ + if( rxDataSeries.is() ) try + { + PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) ); + lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, false ); + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +DataLabelsConverter::DataLabelsConverter( const ConverterRoot& rParent, DataLabelsModel& rModel ) : + ConverterBase< DataLabelsModel >( rParent, rModel ) +{ +} + +DataLabelsConverter::~DataLabelsConverter() +{ +} + +void DataLabelsConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, const TypeGroupConverter& rTypeGroup ) +{ + if( !mrModel.mbDeleted ) + { + PropertySet aPropSet( rxDataSeries ); + lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, true ); + } + + // data point label settings + for( DataLabelsModel::DataLabelVector::iterator aIt = mrModel.maPointLabels.begin(), aEnd = mrModel.maPointLabels.end(); aIt != aEnd; ++aIt ) + { + DataLabelConverter aLabelConv( *this, **aIt ); + aLabelConv.convertFromModel( rxDataSeries, rTypeGroup ); + } +} + +// ============================================================================ + +ErrorBarConverter::ErrorBarConverter( const ConverterRoot& rParent, ErrorBarModel& rModel ) : + ConverterBase< ErrorBarModel >( rParent, rModel ) +{ +} + +ErrorBarConverter::~ErrorBarConverter() +{ +} + +void ErrorBarConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries ) +{ + bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both); + bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both); + if( bShowPos || bShowNeg ) try + { + Reference< XPropertySet > xErrorBar( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.ErrorBar" ) ), UNO_QUERY_THROW ); + PropertySet aBarProp( xErrorBar ); + + // plus/minus bars + aBarProp.setProperty( PROP_ShowPositiveError, bShowPos ); + aBarProp.setProperty( PROP_ShowNegativeError, bShowNeg ); + + // type of displayed error + namespace cssc = ::com::sun::star::chart; + switch( mrModel.mnValueType ) + { + case XML_cust: + { + // #i87806# manual error bars + aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::FROM_DATA ); + // attach data sequences to erorr bar + Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY ); + if( xDataSink.is() ) + { + // create vector of all value sequences + ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec; + // add positive values + if( bShowPos ) + { + Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::PLUS ); + if( xValueSeq.is() ) + aLabeledSeqVec.push_back( xValueSeq ); + } + // add negative values + if( bShowNeg ) + { + Reference< XLabeledDataSequence > xValueSeq = createLabeledDataSequence( ErrorBarModel::MINUS ); + if( xValueSeq.is() ) + aLabeledSeqVec.push_back( xValueSeq ); + } + // attach labeled data sequences to series + if( aLabeledSeqVec.empty() ) + xErrorBar.clear(); + else + xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) ); + } + } + break; + case XML_fixedVal: + aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::ABSOLUTE ); + aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue ); + aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue ); + break; + case XML_percentage: + aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::RELATIVE ); + aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue ); + aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue ); + break; + case XML_stdDev: + aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_DEVIATION ); + aBarProp.setProperty( PROP_Weight, mrModel.mfValue ); + break; + case XML_stdErr: + aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_ERROR ); + break; + default: + OSL_ENSURE( false, "ErrorBarConverter::convertFromModel - unknown error bar type" ); + xErrorBar.clear(); + } + + // error bar formatting + getFormatter().convertFrameFormatting( aBarProp, mrModel.mxShapeProp, OBJECTTYPE_ERRORBAR ); + + if( xErrorBar.is() ) + { + PropertySet aSeriesProp( rxDataSeries ); + switch( mrModel.mnDirection ) + { + case XML_x: aSeriesProp.setProperty( PROP_ErrorBarX, xErrorBar ); break; + case XML_y: aSeriesProp.setProperty( PROP_ErrorBarY, xErrorBar ); break; + default: OSL_ENSURE( false, "ErrorBarConverter::convertFromModel - invalid error bar direction" ); + } + } + } + catch( Exception& ) + { + OSL_ENSURE( false, "ErrorBarConverter::convertFromModel - error while creating error bars" ); + } +} + +// private -------------------------------------------------------------------- + +Reference< XLabeledDataSequence > ErrorBarConverter::createLabeledDataSequence( ErrorBarModel::SourceType eSourceType ) +{ + OUString aRole; + switch( eSourceType ) + { + case ErrorBarModel::PLUS: + switch( mrModel.mnDirection ) + { + case XML_x: aRole = CREATE_OUSTRING( "error-bars-x-positive" ); break; + case XML_y: aRole = CREATE_OUSTRING( "error-bars-y-positive" ); break; + } + break; + case ErrorBarModel::MINUS: + switch( mrModel.mnDirection ) + { + case XML_x: aRole = CREATE_OUSTRING( "error-bars-x-negative" ); break; + case XML_y: aRole = CREATE_OUSTRING( "error-bars-y-negative" ); break; + } + break; + } + OSL_ENSURE( aRole.getLength() > 0, "ErrorBarConverter::createLabeledDataSequence - invalid error bar direction" ); + return lclCreateLabeledDataSequence( *this, mrModel.maSources.get( eSourceType ).get(), aRole ); +} + +// ============================================================================ + +TrendlineLabelConverter::TrendlineLabelConverter( const ConverterRoot& rParent, TrendlineLabelModel& rModel ) : + ConverterBase< TrendlineLabelModel >( rParent, rModel ) +{ +} + +TrendlineLabelConverter::~TrendlineLabelConverter() +{ +} + +void TrendlineLabelConverter::convertFromModel( PropertySet& rPropSet ) +{ + // formatting + getFormatter().convertFormatting( rPropSet, mrModel.mxShapeProp, mrModel.mxTextProp, OBJECTTYPE_TRENDLINELABEL ); +} + +// ============================================================================ + +TrendlineConverter::TrendlineConverter( const ConverterRoot& rParent, TrendlineModel& rModel ) : + ConverterBase< TrendlineModel >( rParent, rModel ) +{ +} + +TrendlineConverter::~TrendlineConverter() +{ +} + +void TrendlineConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries ) +{ + try + { + // trend line type + OUString aServiceName; + switch( mrModel.mnTypeId ) + { + case XML_exp: aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.ExponentialRegressionCurve" ); break; + case XML_linear: aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.LinearRegressionCurve" ); break; + case XML_log: aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.LogarithmicRegressionCurve" ); break; + case XML_movingAvg: /* #i66819# moving average trendlines not supported */ break; + case XML_poly: /* #i20819# polynomial trendlines not supported */ break; + case XML_power: aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.PotentialRegressionCurve" ); break; + default: OSL_ENSURE( false, "TrendlineConverter::convertFromModel - unknown trendline type" ); + } + if( aServiceName.getLength() > 0 ) + { + Reference< XRegressionCurve > xRegCurve( createInstance( aServiceName ), UNO_QUERY_THROW ); + PropertySet aPropSet( xRegCurve ); + + // trendline formatting + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, OBJECTTYPE_TRENDLINE ); + + // #i83100# show equation and correlation coefficient + PropertySet aLabelProp( xRegCurve->getEquationProperties() ); + aLabelProp.setProperty( PROP_ShowEquation, mrModel.mbDispEquation ); + aLabelProp.setProperty( PROP_ShowCorrelationCoefficient, mrModel.mbDispRSquared ); + + // #i83100# formatting of the equation text box + if( mrModel.mbDispEquation || mrModel.mbDispRSquared ) + { + TrendlineLabelConverter aLabelConv( *this, mrModel.mxLabel.getOrCreate() ); + aLabelConv.convertFromModel( aLabelProp ); + } + + // unsupported: #i5085# manual trendline size + // unsupported: #i34093# manual crossing point + + Reference< XRegressionCurveContainer > xRegCurveCont( rxDataSeries, UNO_QUERY_THROW ); + xRegCurveCont->addRegressionCurve( xRegCurve ); + } + } + catch( Exception& ) + { + OSL_ENSURE( false, "TrendlineConverter::convertFromModel - error while creating trendline" ); + } +} + +// ============================================================================ + +DataPointConverter::DataPointConverter( const ConverterRoot& rParent, DataPointModel& rModel ) : + ConverterBase< DataPointModel >( rParent, rModel ) +{ +} + +DataPointConverter::~DataPointConverter() +{ +} + +void DataPointConverter::convertFromModel( const Reference< XDataSeries >& rxDataSeries, + const TypeGroupConverter& rTypeGroup, const SeriesModel& rSeries ) +{ + try + { + PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) ); + + // data point marker + if( mrModel.monMarkerSymbol.differsFrom( rSeries.mnMarkerSymbol ) || mrModel.monMarkerSize.differsFrom( rSeries.mnMarkerSize ) ) + rTypeGroup.convertMarker( aPropSet, mrModel.monMarkerSymbol.get( rSeries.mnMarkerSymbol ), mrModel.monMarkerSize.get( rSeries.mnMarkerSize ) ); + + // data point pie explosion + if( mrModel.monExplosion.differsFrom( rSeries.mnExplosion ) ) + rTypeGroup.convertPieExplosion( aPropSet, mrModel.monExplosion.get() ); + + // point formatting + if( mrModel.mxShapeProp.is() ) + { + if( rTypeGroup.getTypeInfo().mbPictureOptions ) + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(), rTypeGroup.getSeriesObjectType(), rSeries.mnIndex ); + else + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex ); + } + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +SeriesConverter::SeriesConverter( const ConverterRoot& rParent, SeriesModel& rModel ) : + ConverterBase< SeriesModel >( rParent, rModel ) +{ +} + +SeriesConverter::~SeriesConverter() +{ +} + +Reference< XLabeledDataSequence > SeriesConverter::createCategorySequence( const OUString& rRole ) +{ + return createLabeledDataSequence( SeriesModel::CATEGORIES, rRole, false ); +} + +Reference< XLabeledDataSequence > SeriesConverter::createValueSequence( const OUString& rRole ) +{ + return createLabeledDataSequence( SeriesModel::VALUES, rRole, true ); +} + +Reference< XDataSeries > SeriesConverter::createDataSeries( const TypeGroupConverter& rTypeGroup, bool bVaryColorsByPoint ) +{ + const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo(); + + // create the data series object + Reference< XDataSeries > xDataSeries( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.DataSeries" ) ), UNO_QUERY ); + PropertySet aSeriesProp( xDataSeries ); + + // attach data and title sequences to series + sal_Int32 nDataPointCount = 0; + Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY ); + if( xDataSink.is() ) + { + // create vector of all value sequences + ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec; + // add Y values + Reference< XLabeledDataSequence > xYValueSeq = createValueSequence( CREATE_OUSTRING( "values-y" ) ); + if( xYValueSeq.is() ) + { + aLabeledSeqVec.push_back( xYValueSeq ); + Reference< XDataSequence > xValues = xYValueSeq->getValues(); + if( xValues.is() ) + nDataPointCount = xValues->getData().getLength(); + } + // add X values of scatter and bubble charts + if( !rTypeInfo.mbCategoryAxis ) + { + Reference< XLabeledDataSequence > xXValueSeq = createCategorySequence( CREATE_OUSTRING( "values-x" ) ); + if( xXValueSeq.is() ) + aLabeledSeqVec.push_back( xXValueSeq ); + // add size values of bubble charts + if( rTypeInfo.meTypeId == TYPEID_BUBBLE ) + { + Reference< XLabeledDataSequence > xSizeValueSeq = createLabeledDataSequence( SeriesModel::POINTS, CREATE_OUSTRING( "values-size" ), true ); + if( xSizeValueSeq.is() ) + aLabeledSeqVec.push_back( xSizeValueSeq ); + } + } + // attach labeled data sequences to series + if( !aLabeledSeqVec.empty() ) + xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) ); + } + + // error bars + for( SeriesModel::ErrorBarVector::iterator aIt = mrModel.maErrorBars.begin(), aEnd = mrModel.maErrorBars.end(); aIt != aEnd; ++aIt ) + { + ErrorBarConverter aErrorBarConv( *this, **aIt ); + aErrorBarConv.convertFromModel( xDataSeries ); + } + + // trendlines + for( SeriesModel::TrendlineVector::iterator aIt = mrModel.maTrendlines.begin(), aEnd = mrModel.maTrendlines.end(); aIt != aEnd; ++aIt ) + { + TrendlineConverter aTrendlineConv( *this, **aIt ); + aTrendlineConv.convertFromModel( xDataSeries ); + } + + // data point markers + rTypeGroup.convertMarker( aSeriesProp, mrModel.mnMarkerSymbol, mrModel.mnMarkerSize ); +#if OOX_CHART_SMOOTHED_PER_SERIES + // #i66858# smoothed series lines + rTypeGroup.convertLineSmooth( aSeriesProp, mrModel.mbSmooth ); +#endif + // 3D bar style (not possible to set at chart type -> set at all series) + rTypeGroup.convertBarGeometry( aSeriesProp, mrModel.monShape.get( rTypeGroup.getModel().mnShape ) ); + // pie explosion (restricted to [0%,100%] in Chart2) + rTypeGroup.convertPieExplosion( aSeriesProp, mrModel.mnExplosion ); + + // series formatting + ObjectFormatter& rFormatter = getFormatter(); + ObjectType eObjType = rTypeGroup.getSeriesObjectType(); + if( rTypeInfo.mbPictureOptions ) + rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(), eObjType, mrModel.mnIndex ); + else + rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, eObjType, mrModel.mnIndex ); + + // set the (unused) property default value used by the Chart2 templates (true for pie/doughnut charts) + bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE; + aSeriesProp.setProperty( PROP_VaryColorsByPoint, bIsPie ); + + // own area formatting for every data point (TODO: varying line color not supported) + // #i91271# always set area formatting for every point in pie/doughnut charts to override their automatic point formatting + if( bIsPie || (bVaryColorsByPoint && rTypeGroup.isSeriesFrameFormat() && ObjectFormatter::isAutomaticFill( mrModel.mxShapeProp )) ) + { + /* Set the series point number as color cycle size at the object + formatter to get correct start-shade/end-tint. TODO: in doughnut + charts, the sizes of the series may vary, need to use the maximum + point count of all series. */ + sal_Int32 nOldMax = rFormatter.getMaxSeriesIndex(); + if( bVaryColorsByPoint ) + rFormatter.setMaxSeriesIndex( nDataPointCount - 1 ); + for( sal_Int32 nIndex = 0; nIndex < nDataPointCount; ++nIndex ) + { + try + { + PropertySet aPointProp( xDataSeries->getDataPointByIndex( nIndex ) ); + rFormatter.convertAutomaticFill( aPointProp, eObjType, bVaryColorsByPoint ? nIndex : mrModel.mnIndex ); + } + catch( Exception& ) + { + } + } + rFormatter.setMaxSeriesIndex( nOldMax ); + } + + // data point settings + for( SeriesModel::DataPointVector::iterator aIt = mrModel.maPoints.begin(), aEnd = mrModel.maPoints.end(); aIt != aEnd; ++aIt ) + { + DataPointConverter aPointConv( *this, **aIt ); + aPointConv.convertFromModel( xDataSeries, rTypeGroup, mrModel ); + } + + /* Series data label settings. If and only if the series does not contain + a c:dLbls element, then the c:dLbls element of the parent chart type is + used (data label settings of the parent chart type are *not* merged + into own existing data label settings). */ + ModelRef< DataLabelsModel > xLabels = mrModel.mxLabels.is() ? mrModel.mxLabels : rTypeGroup.getModel().mxLabels; + if( xLabels.is() ) + { + DataLabelsConverter aLabelsConv( *this, *xLabels ); + aLabelsConv.convertFromModel( xDataSeries, rTypeGroup ); + } + + return xDataSeries; +} + +// private -------------------------------------------------------------------- + +Reference< XLabeledDataSequence > SeriesConverter::createLabeledDataSequence( + SeriesModel::SourceType eSourceType, const OUString& rRole, bool bUseTextLabel ) +{ + DataSourceModel* pValues = mrModel.maSources.get( eSourceType ).get(); + TextModel* pTitle = bUseTextLabel ? mrModel.mxText.get() : 0; + return lclCreateLabeledDataSequence( *this, pValues, rRole, pTitle ); +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/seriesmodel.cxx b/oox/source/drawingml/chart/seriesmodel.cxx new file mode 100644 index 000000000000..01fff8e8d385 --- /dev/null +++ b/oox/source/drawingml/chart/seriesmodel.cxx @@ -0,0 +1,157 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/seriesmodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +DataLabelModelBase::DataLabelModelBase() : + mbDeleted( false ) +{ +} + +DataLabelModelBase::~DataLabelModelBase() +{ +} + +// ============================================================================ + +DataLabelModel::DataLabelModel() : + mnIndex( -1 ) +{ +} + +DataLabelModel::~DataLabelModel() +{ +} + +// ============================================================================ + +DataLabelsModel::DataLabelsModel() : + mbShowLeaderLines( false ) +{ +} + +DataLabelsModel::~DataLabelsModel() +{ +} + +// ============================================================================ + +PictureOptionsModel::PictureOptionsModel() : + mfStackUnit( 1.0 ), + mnPictureFormat( XML_stretch ), + mbApplyToFront( false ), + mbApplyToSides( false ), + mbApplyToEnd( false ) +{ +} + +PictureOptionsModel::~PictureOptionsModel() +{ +} + +// ============================================================================ + +ErrorBarModel::ErrorBarModel() : + mfValue( 0.0 ), + mnDirection( XML_y ), + mnTypeId( XML_both ), + mnValueType( XML_fixedVal ), + mbNoEndCap( false ) +{ +} + +ErrorBarModel::~ErrorBarModel() +{ +} + +// ============================================================================ + +TrendlineLabelModel::TrendlineLabelModel() +{ +} + +TrendlineLabelModel::~TrendlineLabelModel() +{ +} + +// ============================================================================ + +TrendlineModel::TrendlineModel() : + mnOrder( 2 ), + mnPeriod( 2 ), + mnTypeId( XML_linear ), + mbDispEquation( false ), + mbDispRSquared( false ) +{ +} + +TrendlineModel::~TrendlineModel() +{ +} + +// ============================================================================ + +DataPointModel::DataPointModel() : + mnIndex( -1 ), + mbInvertNeg( false ) +{ +} + +DataPointModel::~DataPointModel() +{ +} + +// ============================================================================ + +SeriesModel::SeriesModel() : + mnExplosion( 0 ), + mnIndex( -1 ), + mnMarkerSize( 5 ), + mnMarkerSymbol( XML_auto ), + mnOrder( -1 ), + mbBubble3d( false ), + mbInvertNeg( false ), + mbSmooth( false ) +{ +} + +SeriesModel::~SeriesModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/titlecontext.cxx b/oox/source/drawingml/chart/titlecontext.cxx new file mode 100644 index 000000000000..5ff71109b710 --- /dev/null +++ b/oox/source/drawingml/chart/titlecontext.cxx @@ -0,0 +1,163 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/titlecontext.hxx" +#include "oox/drawingml/shapepropertiescontext.hxx" +#include "oox/drawingml/textbodycontext.hxx" +#include "oox/drawingml/chart/datasourcecontext.hxx" +#include "oox/drawingml/chart/titlemodel.hxx" + +using ::rtl::OUString; +using ::oox::core::ContextHandler2Helper; +using ::oox::core::ContextHandlerRef; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +TextContext::TextContext( ContextHandler2Helper& rParent, TextModel& rModel ) : + ContextBase< TextModel >( rParent, rModel ) +{ +} + +TextContext::~TextContext() +{ +} + +ContextHandlerRef TextContext::onCreateContext( sal_Int32 nElement, const AttributeList& ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( tx ): + switch( nElement ) + { + case C_TOKEN( rich ): + return new TextBodyContext( *this, mrModel.mxTextBody.create() ); + case C_TOKEN( strRef ): + OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - multiple data sequences" ); + return new StringSequenceContext( *this, mrModel.mxDataSeq.create() ); + case C_TOKEN( v ): + OSL_ENSURE( !mrModel.mxDataSeq, "TextContext::onCreateContext - multiple data sequences" ); + return this; // collect value in onEndElement() + } + break; + } + return 0; +} + +void TextContext::onEndElement( const OUString& rChars ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( v ): + // store as single string sequence element + mrModel.mxDataSeq.create().maData[ 0 ] <<= rChars; + break; + } +} + +// ============================================================================ + +TitleContext::TitleContext( ContextHandler2Helper& rParent, TitleModel& rModel ) : + ContextBase< TitleModel >( rParent, rModel ) +{ +} + +TitleContext::~TitleContext() +{ +} + +ContextHandlerRef TitleContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( title ): + switch( nElement ) + { + case C_TOKEN( layout ): + return new LayoutContext( *this, mrModel.mxLayout.create() ); + case C_TOKEN( overlay ): + // default is 'false', not 'true' as specified + mrModel.mbOverlay = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( tx ): + return new TextContext( *this, mrModel.mxText.create() ); + case C_TOKEN( txPr ): + return new TextBodyContext( *this, mrModel.mxTextProp.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +LegendContext::LegendContext( ContextHandler2Helper& rParent, LegendModel& rModel ) : + ContextBase< LegendModel >( rParent, rModel ) +{ +} + +LegendContext::~LegendContext() +{ +} + +ContextHandlerRef LegendContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( legend ): + switch( nElement ) + { + case C_TOKEN( layout ): + return new LayoutContext( *this, mrModel.mxLayout.create() ); + case C_TOKEN( legendPos ): + mrModel.mnPosition = rAttribs.getToken( XML_val, XML_r ); + return 0; + case C_TOKEN( overlay ): + // default is 'false', not 'true' as specified + mrModel.mbOverlay = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( spPr ): + return new ShapePropertiesContext( *this, mrModel.mxShapeProp.create() ); + case C_TOKEN( txPr ): + return new TextBodyContext( *this, mrModel.mxTextProp.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/titleconverter.cxx b/oox/source/drawingml/chart/titleconverter.cxx new file mode 100644 index 000000000000..bca53f1a2c01 --- /dev/null +++ b/oox/source/drawingml/chart/titleconverter.cxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/titleconverter.hxx" +#include <com/sun/star/chart2/LegendExpansion.hpp> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart2/XDiagram.hpp> +#include <com/sun/star/chart2/XFormattedString.hpp> +#include <com/sun/star/chart2/XLegend.hpp> +#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/chart2/XTitled.hpp> +#include "properties.hxx" +#include "oox/drawingml/textbody.hxx" +#include "oox/drawingml/textparagraph.hxx" +#include "oox/drawingml/chart/datasourceconverter.hxx" +#include "oox/drawingml/chart/titlemodel.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::awt::Rectangle; +using ::com::sun::star::chart2::XDiagram; +using ::com::sun::star::chart2::XFormattedString; +using ::com::sun::star::chart2::XLegend; +using ::com::sun::star::chart2::XTitle; +using ::com::sun::star::chart2::XTitled; +using ::com::sun::star::chart2::data::XDataSequence; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +TextConverter::TextConverter( const ConverterRoot& rParent, TextModel& rModel ) : + ConverterBase< TextModel >( rParent, rModel ) +{ +} + +TextConverter::~TextConverter() +{ +} + +Reference< XDataSequence > TextConverter::createDataSequence( const OUString& rRole ) +{ + Reference< XDataSequence > xDataSeq; + if( mrModel.mxDataSeq.is() ) + { + DataSequenceConverter aDataSeqConv( *this, *mrModel.mxDataSeq ); + xDataSeq = aDataSeqConv.createDataSequence( rRole ); + } + return xDataSeq; +} + +Sequence< Reference< XFormattedString > > TextConverter::createStringSequence( + const OUString& rDefaultText, const ModelRef< TextBody >& rxTextProp, ObjectType eObjType ) +{ + OSL_ENSURE( !mrModel.mxDataSeq || !mrModel.mxTextBody, "TextConverter::createStringSequence - linked string and rich text found" ); + ::std::vector< Reference< XFormattedString > > aStringVec; + if( mrModel.mxTextBody.is() ) + { + // rich-formatted text objects can be created, but currently Chart2 is not able to show them + const TextParagraphVector& rTextParas = mrModel.mxTextBody->getParagraphs(); + for( TextParagraphVector::const_iterator aPIt = rTextParas.begin(), aPEnd = rTextParas.end(); aPIt != aPEnd; ++aPIt ) + { + const TextParagraph& rTextPara = **aPIt; + const TextCharacterProperties& rParaProps = rTextPara.getProperties().getTextCharacterProperties(); + for( TextRunVector::const_iterator aRIt = rTextPara.getRuns().begin(), aREnd = rTextPara.getRuns().end(); aRIt != aREnd; ++aRIt ) + { + const TextRun& rTextRun = **aRIt; + bool bAddNewLine = (aRIt + 1 == aREnd) && (aPIt + 1 != aPEnd); + Reference< XFormattedString > xFmtStr = appendFormattedString( aStringVec, rTextRun.getText(), bAddNewLine ); + PropertySet aPropSet( xFmtStr ); + TextCharacterProperties aRunProps( rParaProps ); + aRunProps.assignUsed( rTextRun.getTextCharacterProperties() ); + getFormatter().convertTextFormatting( aPropSet, aRunProps, eObjType ); + } + } + } + else + { + OUString aString; + // try to create string from linked data + if( mrModel.mxDataSeq.is() && !mrModel.mxDataSeq->maData.empty() ) + mrModel.mxDataSeq->maData.begin()->second >>= aString; + // no linked string -> fall back to default string + if( aString.getLength() == 0 ) + aString = rDefaultText; + + // create formatted string object + if( aString.getLength() > 0 ) + { + Reference< XFormattedString > xFmtStr = appendFormattedString( aStringVec, aString, false ); + PropertySet aPropSet( xFmtStr ); + getFormatter().convertTextFormatting( aPropSet, rxTextProp, eObjType ); + } + } + + return ContainerHelper::vectorToSequence( aStringVec ); +} + +Reference< XFormattedString > TextConverter::appendFormattedString( + ::std::vector< Reference< XFormattedString > >& orStringVec, const OUString& rString, bool bAddNewLine ) const +{ + Reference< XFormattedString > xFmtStr; + try + { + xFmtStr.set( ConverterRoot::createInstance( CREATE_OUSTRING( "com.sun.star.chart2.FormattedString" ) ), UNO_QUERY_THROW ); + xFmtStr->setString( bAddNewLine ? (rString + OUString( sal_Unicode( '\n' ) )) : rString ); + orStringVec.push_back( xFmtStr ); + } + catch( Exception& ) + { + } + return xFmtStr; +} + +// ============================================================================ + +TitleConverter::TitleConverter( const ConverterRoot& rParent, TitleModel& rModel ) : + ConverterBase< TitleModel >( rParent, rModel ) +{ +} + +TitleConverter::~TitleConverter() +{ +} + +void TitleConverter::convertFromModel( const Reference< XTitled >& rxTitled, const OUString& rAutoTitle, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx ) +{ + if( rxTitled.is() ) + { + // create the formatted strings + TextModel& rText = mrModel.mxText.getOrCreate(); + TextConverter aTextConv( *this, rText ); + Sequence< Reference< XFormattedString > > aStringSeq = aTextConv.createStringSequence( rAutoTitle, mrModel.mxTextProp, eObjType ); + if( aStringSeq.hasElements() ) try + { + // create the title object and set the string data + Reference< XTitle > xTitle( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.Title" ) ), UNO_QUERY_THROW ); + xTitle->setText( aStringSeq ); + rxTitled->setTitleObject( xTitle ); + + // frame formatting (text formatting already done in TextConverter::createStringSequence()) + PropertySet aPropSet( xTitle ); + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, eObjType ); + + // frame rotation + OSL_ENSURE( !mrModel.mxTextProp || !rText.mxTextBody, "TitleConverter::convertFromModel - multiple text properties" ); + ModelRef< TextBody > xTextProp = mrModel.mxTextProp.is() ? mrModel.mxTextProp : rText.mxTextBody; + getFormatter().convertTextRotation( aPropSet, xTextProp, true ); + + // register the title and layout data for conversion of position + registerTitleLayout( xTitle, mrModel.mxLayout, eObjType, nMainIdx, nSubIdx ); + } + catch( Exception& ) + { + } + } +} + +// ============================================================================ + +LegendConverter::LegendConverter( const ConverterRoot& rParent, LegendModel& rModel ) : + ConverterBase< LegendModel >( rParent, rModel ) +{ +} + +LegendConverter::~LegendConverter() +{ +} + +void LegendConverter::convertFromModel( const Reference< XDiagram >& rxDiagram ) +{ + if( rxDiagram.is() ) try + { + namespace cssc2 = ::com::sun::star::chart2; + + // create the legend + Reference< XLegend > xLegend( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.Legend" ) ), UNO_QUERY_THROW ); + rxDiagram->setLegend( xLegend ); + PropertySet aPropSet( xLegend ); + aPropSet.setProperty( PROP_Show, true ); + + // legend formatting + getFormatter().convertFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxTextProp, OBJECTTYPE_LEGEND ); + + // predefined legend position and expansion + cssc2::LegendPosition eLegendPos = cssc2::LegendPosition_CUSTOM; + cssc2::LegendExpansion eLegendExpand = cssc2::LegendExpansion_HIGH; + switch( mrModel.mnPosition ) + { + case XML_l: + eLegendPos = cssc2::LegendPosition_LINE_START; + eLegendExpand = cssc2::LegendExpansion_HIGH; + break; + case XML_r: + eLegendPos = cssc2::LegendPosition_LINE_END; + eLegendExpand = cssc2::LegendExpansion_HIGH; + break; + case XML_t: + eLegendPos = cssc2::LegendPosition_PAGE_START; + eLegendExpand = cssc2::LegendExpansion_WIDE; + break; + case XML_b: + eLegendPos = cssc2::LegendPosition_PAGE_END; + eLegendExpand = cssc2::LegendExpansion_WIDE; + break; + case XML_tr: + eLegendPos = cssc2::LegendPosition_LINE_END; // top-right not supported + eLegendExpand = cssc2::LegendExpansion_HIGH; + break; + } + + // manual positioning + LayoutModel& rLayout = mrModel.mxLayout.getOrCreate(); + LayoutConverter aLayoutConv( *this, rLayout ); + aLayoutConv.convertFromModel( aPropSet ); + Rectangle aLegendRect; + if( aLayoutConv.calcAbsRectangle( aLegendRect ) ) + { + // #i71697# it is not possible to set the size directly, do some magic here + double fRatio = static_cast< double >( aLegendRect.Width ) / aLegendRect.Height; + if( fRatio > 1.5 ) + eLegendExpand = cssc2::LegendExpansion_WIDE; + else if( fRatio < 0.75 ) + eLegendExpand = cssc2::LegendExpansion_HIGH; + else + eLegendExpand = cssc2::LegendExpansion_BALANCED; + } + + // set position and expansion properties + aPropSet.setProperty( PROP_AnchorPosition, eLegendPos ); + aPropSet.setProperty( PROP_Expansion, eLegendExpand ); + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/titlemodel.cxx b/oox/source/drawingml/chart/titlemodel.cxx new file mode 100644 index 000000000000..bb5501e05f32 --- /dev/null +++ b/oox/source/drawingml/chart/titlemodel.cxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/titlemodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +TextModel::TextModel() +{ +} + +TextModel::~TextModel() +{ +} + +// ============================================================================ + +TitleModel::TitleModel() : + mbOverlay( false ) +{ +} + +TitleModel::~TitleModel() +{ +} + +// ============================================================================ + +LegendModel::LegendModel() : + mnPosition( XML_r ), + mbOverlay( false ) +{ +} + +LegendModel::~LegendModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/typegroupcontext.cxx b/oox/source/drawingml/chart/typegroupcontext.cxx new file mode 100644 index 000000000000..972295304593 --- /dev/null +++ b/oox/source/drawingml/chart/typegroupcontext.cxx @@ -0,0 +1,402 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/typegroupcontext.hxx" +#include "oox/drawingml/chart/seriescontext.hxx" +#include "oox/drawingml/chart/typegroupmodel.hxx" + +using ::oox::core::ContextHandler2Helper; +using ::oox::core::ContextHandlerRef; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +UpDownBarsContext::UpDownBarsContext( ContextHandler2Helper& rParent, UpDownBarsModel& rModel ) : + ContextBase< UpDownBarsModel >( rParent, rModel ) +{ +} + +UpDownBarsContext::~UpDownBarsContext() +{ +} + +ContextHandlerRef UpDownBarsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case C_TOKEN( upDownBars ): + switch( nElement ) + { + case C_TOKEN( downBars ): + return new ShapePrWrapperContext( *this, mrModel.mxDownBars.create() ); + case C_TOKEN( gapWidth ): + mrModel.mnGapWidth = rAttribs.getInteger( XML_val, 150 ); + return 0; + case C_TOKEN( upBars ): + return new ShapePrWrapperContext( *this, mrModel.mxUpBars.create() ); + } + break; + } + return 0; +} + +// ============================================================================ + +AreaTypeGroupContext::AreaTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +AreaTypeGroupContext::~AreaTypeGroupContext() +{ +} + +ContextHandlerRef AreaTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dropLines ): + return new ShapePrWrapperContext( *this, mrModel.mxDropLines.create() ); + case C_TOKEN( gapDepth ): + mrModel.mnGapDepth = rAttribs.getInteger( XML_val, 150 ); + return 0; + case C_TOKEN( grouping ): + mrModel.mnGrouping = rAttribs.getToken( XML_val, XML_standard ); + return 0; + case C_TOKEN( ser ): + return new AreaSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +BarTypeGroupContext::BarTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +BarTypeGroupContext::~BarTypeGroupContext() +{ +} + +ContextHandlerRef BarTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( barDir ): + mrModel.mnBarDir = rAttribs.getToken( XML_val, XML_col ); + return 0; + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( gapDepth ): + mrModel.mnGapDepth = rAttribs.getInteger( XML_val, 150 ); + return 0; + case C_TOKEN( gapWidth ): + mrModel.mnGapWidth = rAttribs.getInteger( XML_val, 150 ); + return 0; + case C_TOKEN( grouping ): + // default is 'standard', not 'clustered' as specified + mrModel.mnGrouping = rAttribs.getToken( XML_val, XML_standard ); + return 0; + case C_TOKEN( overlap ): + mrModel.mnOverlap = rAttribs.getInteger( XML_val, 0 ); + return 0; + case C_TOKEN( ser ): + return new BarSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( serLines ): + return new ShapePrWrapperContext( *this, mrModel.mxSerLines.create() ); + case C_TOKEN( shape ): + mrModel.mnShape = rAttribs.getToken( XML_val, XML_box ); + return 0; + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +BubbleTypeGroupContext::BubbleTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +BubbleTypeGroupContext::~BubbleTypeGroupContext() +{ +} + +ContextHandlerRef BubbleTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( bubble3D ): + // default is 'false', not 'true' as specified + mrModel.mbBubble3d = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( bubbleScale ): + mrModel.mnBubbleScale = rAttribs.getInteger( XML_val, 100 ); + return 0; + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( ser ): + return new BubbleSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( showNegBubbles ): + // default is 'false', not 'true' as specified + mrModel.mbShowNegBubbles = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( sizeRepresents ): + mrModel.mnSizeRepresents = rAttribs.getToken( XML_val, XML_area ); + return 0; + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +LineTypeGroupContext::LineTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +LineTypeGroupContext::~LineTypeGroupContext() +{ +} + +ContextHandlerRef LineTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( dropLines ): + return new ShapePrWrapperContext( *this, mrModel.mxDropLines.create() ); + case C_TOKEN( gapDepth ): + mrModel.mnGapDepth = rAttribs.getInteger( XML_val, 150 ); + return 0; + case C_TOKEN( grouping ): + mrModel.mnGrouping = rAttribs.getToken( XML_val, XML_standard ); + return 0; + case C_TOKEN( hiLowLines ): + return new ShapePrWrapperContext( *this, mrModel.mxHiLowLines.create() ); + case C_TOKEN( marker ): + // default is 'false', not 'true' as specified + mrModel.mbShowMarker = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( ser ): + return new LineSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( smooth ): + // default is 'false', not 'true' as specified + mrModel.mbSmooth = rAttribs.getBool( XML_val, false ); + return 0; + case C_TOKEN( upDownBars ): + return new UpDownBarsContext( *this, mrModel.mxUpDownBars.create() ); + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +PieTypeGroupContext::PieTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +PieTypeGroupContext::~PieTypeGroupContext() +{ +} + +ContextHandlerRef PieTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( firstSliceAng ): + mrModel.mnFirstAngle = rAttribs.getInteger( XML_val, 0 ); + return 0; + case C_TOKEN( gapWidth ): + mrModel.mnGapWidth = rAttribs.getInteger( XML_val, 150 ); + return 0; + case C_TOKEN( holeSize ): + mrModel.mnHoleSize = rAttribs.getInteger( XML_val, 10 ); + return 0; + case C_TOKEN( ofPieType ): + mrModel.mnOfPieType = rAttribs.getToken( XML_val, XML_pie ); + return 0; + case C_TOKEN( secondPieSize ): + mrModel.mnSecondPieSize = rAttribs.getInteger( XML_val, 75 ); + return 0; + case C_TOKEN( ser ): + return new PieSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( serLines ): + return new ShapePrWrapperContext( *this, mrModel.mxSerLines.create() ); + case C_TOKEN( splitPos ): + mrModel.mfSplitPos = rAttribs.getDouble( XML_val, 0.0 ); + return 0; + case C_TOKEN( splitType ): + mrModel.mnSplitType = rAttribs.getToken( XML_val, XML_auto ); + return 0; + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +RadarTypeGroupContext::RadarTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +RadarTypeGroupContext::~RadarTypeGroupContext() +{ +} + +ContextHandlerRef RadarTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( radarStyle ): + mrModel.mnRadarStyle = rAttribs.getToken( XML_val, XML_standard ); + return 0; + case C_TOKEN( ser ): + return new RadarSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +ScatterTypeGroupContext::ScatterTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +ScatterTypeGroupContext::~ScatterTypeGroupContext() +{ +} + +ContextHandlerRef ScatterTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( dLbls ): + return new DataLabelsContext( *this, mrModel.mxLabels.create() ); + case C_TOKEN( scatterStyle ): + mrModel.mnScatterStyle = rAttribs.getInteger( XML_val, XML_marker ); + return 0; + case C_TOKEN( ser ): + return new ScatterSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( varyColors ): + // default is 'false', not 'true' as specified + mrModel.mbVaryColors = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +SurfaceTypeGroupContext::SurfaceTypeGroupContext( ContextHandler2Helper& rParent, TypeGroupModel& rModel ) : + TypeGroupContextBase( rParent, rModel ) +{ +} + +SurfaceTypeGroupContext::~SurfaceTypeGroupContext() +{ +} + +ContextHandlerRef SurfaceTypeGroupContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() ) switch( nElement ) + { + case C_TOKEN( axId ): + mrModel.maAxisIds.push_back( rAttribs.getInteger( XML_val, -1 ) ); + return 0; + case C_TOKEN( ser ): + return new SurfaceSeriesContext( *this, mrModel.maSeries.create() ); + case C_TOKEN( wireframe ): + // default is 'false', not 'true' as specified + mrModel.mbWireframe = rAttribs.getBool( XML_val, false ); + return 0; + } + return 0; +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/typegroupconverter.cxx b/oox/source/drawingml/chart/typegroupconverter.cxx new file mode 100644 index 000000000000..3746048074e9 --- /dev/null +++ b/oox/source/drawingml/chart/typegroupconverter.cxx @@ -0,0 +1,573 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/typegroupconverter.hxx" +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart2/CurveStyle.hpp> +#include <com/sun/star/chart2/DataPointGeometry3D.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/Symbol.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XCoordinateSystem.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <com/sun/star/chart2/data/XDataSink.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include "oox/drawingml/lineproperties.hxx" +#include "oox/drawingml/chart/seriesconverter.hxx" +#include "oox/drawingml/chart/typegroupmodel.hxx" +#include "properties.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::chart2::XChartType; +using ::com::sun::star::chart2::XChartTypeContainer; +using ::com::sun::star::chart2::XCoordinateSystem; +using ::com::sun::star::chart2::XDataSeries; +using ::com::sun::star::chart2::XDataSeriesContainer; +using ::com::sun::star::chart2::XDiagram; +using ::com::sun::star::chart2::data::XDataSink; +using ::com::sun::star::chart2::data::XLabeledDataSequence; + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +namespace { + +// chart type service names +const sal_Char SERVICE_CHART2_AREA[] = "com.sun.star.chart2.AreaChartType"; +const sal_Char SERVICE_CHART2_CANDLE[] = "com.sun.star.chart2.CandleStickChartType"; +const sal_Char SERVICE_CHART2_COLUMN[] = "com.sun.star.chart2.ColumnChartType"; +const sal_Char SERVICE_CHART2_LINE[] = "com.sun.star.chart2.LineChartType"; +const sal_Char SERVICE_CHART2_NET[] = "com.sun.star.chart2.NetChartType"; +const sal_Char SERVICE_CHART2_FILLEDNET[] = "com.sun.star.chart2.FilledNetChartType"; +const sal_Char SERVICE_CHART2_PIE[] = "com.sun.star.chart2.PieChartType"; +const sal_Char SERVICE_CHART2_SCATTER[] = "com.sun.star.chart2.ScatterChartType"; +const sal_Char SERVICE_CHART2_BUBBLE[] = "com.sun.star.chart2.BubbleChartType"; +const sal_Char SERVICE_CHART2_SURFACE[] = "com.sun.star.chart2.ColumnChartType"; // Todo + +namespace csscd = ::com::sun::star::chart::DataLabelPlacement; + +static const TypeGroupInfo spTypeInfos[] = +{ + // type-id type-category service varied-point-color default label pos comb2d supp3d polar area2d 1stvis xcateg swap stack revers betw picopt + { TYPEID_BAR, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, true, true, false, true, false, true, false, true, false, true, true }, + { TYPEID_HORBAR, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, false, true, false, true, false, true, true, true, false, true, true }, + { TYPEID_LINE, TYPECATEGORY_LINE, SERVICE_CHART2_LINE, VARPOINTMODE_SINGLE, csscd::RIGHT, true, true, false, false, false, true, false, true, false, true, false }, + { TYPEID_AREA, TYPECATEGORY_LINE, SERVICE_CHART2_AREA, VARPOINTMODE_NONE, csscd::CENTER, true, true, false, true, false, true, false, true, true, false, false }, + { TYPEID_STOCK, TYPECATEGORY_LINE, SERVICE_CHART2_CANDLE, VARPOINTMODE_NONE, csscd::RIGHT, true, false, false, false, false, true, false, true, false, true, false }, + { TYPEID_RADARLINE, TYPECATEGORY_RADAR, SERVICE_CHART2_NET, VARPOINTMODE_SINGLE, csscd::TOP, false, false, true, false, false, true, false, false, false, false, false }, + { TYPEID_RADARAREA, TYPECATEGORY_RADAR, SERVICE_CHART2_FILLEDNET, VARPOINTMODE_NONE, csscd::TOP, false, false, true, true, false, true, false, false, true, false, false }, + { TYPEID_PIE, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, true, true, false, false, false, false, false }, + { TYPEID_DOUGHNUT, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, false, true, false, false, false, false, false }, + { TYPEID_OFPIE, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, true, true, false, false, false, false, false }, + { TYPEID_SCATTER, TYPECATEGORY_SCATTER, SERVICE_CHART2_SCATTER, VARPOINTMODE_SINGLE, csscd::RIGHT, true, true, false, false, false, false, false, false, false, false, false }, + { TYPEID_BUBBLE, TYPECATEGORY_SCATTER, SERVICE_CHART2_BUBBLE, VARPOINTMODE_SINGLE, csscd::RIGHT, false, false, false, true, false, false, false, false, false, false, false }, + { TYPEID_SURFACE, TYPECATEGORY_SURFACE, SERVICE_CHART2_SURFACE, VARPOINTMODE_NONE, csscd::RIGHT, false, true, false, true, false, true, false, false, false, false, false } +}; + +static const TypeGroupInfo saUnknownTypeInfo = + { TYPEID_UNKNOWN, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, true, true, false, true, false, true, false, true, false, true, true }; + +const TypeGroupInfo& lclGetTypeInfoFromTypeId( TypeId eTypeId ) +{ + const TypeGroupInfo* pEnd = STATIC_ARRAY_END( spTypeInfos ); + for( const TypeGroupInfo* pIt = spTypeInfos; pIt != pEnd; ++pIt ) + if( pIt->meTypeId == eTypeId ) + return *pIt; + OSL_ENSURE( eTypeId == TYPEID_UNKNOWN, "lclGetTypeInfoFromTypeId - unexpected chart type identifier" ); + return saUnknownTypeInfo; +} + +} // namespace + +// ============================================================================ + +UpDownBarsConverter::UpDownBarsConverter( const ConverterRoot& rParent, UpDownBarsModel& rModel ) : + ConverterBase< UpDownBarsModel >( rParent, rModel ) +{ +} + +UpDownBarsConverter::~UpDownBarsConverter() +{ +} + +void UpDownBarsConverter::convertFromModel( const Reference< XChartType >& rxChartType ) +{ + PropertySet aTypeProp( rxChartType ); + + // upbar format + Reference< XPropertySet > xWhitePropSet; + if( aTypeProp.getProperty( xWhitePropSet, PROP_WhiteDay ) ) + { + PropertySet aPropSet( xWhitePropSet ); + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxUpBars, OBJECTTYPE_UPBAR ); + } + + // downbar format + Reference< XPropertySet > xBlackPropSet; + if( aTypeProp.getProperty( xBlackPropSet, PROP_BlackDay ) ) + { + PropertySet aPropSet( xBlackPropSet ); + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxDownBars, OBJECTTYPE_DOWNBAR ); + } +} + +// ============================================================================ + +TypeGroupConverter::TypeGroupConverter( const ConverterRoot& rParent, TypeGroupModel& rModel ) : + ConverterBase< TypeGroupModel >( rParent, rModel ), + mb3dChart( false ) +{ + TypeId eTypeId = TYPEID_UNKNOWN; + switch( mrModel.mnTypeId ) + { +#define ENSURE_AXESCOUNT( min, max ) OSL_ENSURE( (min <= (int)mrModel.maAxisIds.size()) && ((int)mrModel.maAxisIds.size() <= max), "TypeGroupConverter::TypeGroupConverter - invalid axes count" ) + case C_TOKEN( area3DChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_AREA; mb3dChart = true; break; + case C_TOKEN( areaChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_AREA; mb3dChart = false; break; + case C_TOKEN( bar3DChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_BAR; mb3dChart = true; break; + case C_TOKEN( barChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_BAR; mb3dChart = false; break; + case C_TOKEN( bubbleChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_BUBBLE; mb3dChart = false; break; + case C_TOKEN( doughnutChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_DOUGHNUT; mb3dChart = false; break; + case C_TOKEN( line3DChart ): ENSURE_AXESCOUNT( 3, 3 ); eTypeId = TYPEID_LINE; mb3dChart = true; break; + case C_TOKEN( lineChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_LINE; mb3dChart = false; break; + case C_TOKEN( ofPieChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_OFPIE; mb3dChart = false; break; + case C_TOKEN( pie3DChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_PIE; mb3dChart = true; break; + case C_TOKEN( pieChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_PIE; mb3dChart = false; break; + case C_TOKEN( radarChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_RADARLINE; mb3dChart = false; break; + case C_TOKEN( scatterChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_SCATTER; mb3dChart = false; break; + case C_TOKEN( stockChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_STOCK; mb3dChart = false; break; + case C_TOKEN( surface3DChart ): ENSURE_AXESCOUNT( 3, 3 ); eTypeId = TYPEID_SURFACE; mb3dChart = true; break; + case C_TOKEN( surfaceChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_SURFACE; mb3dChart = true; break; // 3D bar chart from all surface charts + default: OSL_ENSURE( false, "TypeGroupConverter::TypeGroupConverter - unknown chart type" ); +#undef ENSURE_AXESCOUNT + } + + // special handling for some chart types + switch( eTypeId ) + { + case TYPEID_BAR: + if( mrModel.mnBarDir == XML_bar ) + eTypeId = TYPEID_HORBAR; + break; + case TYPEID_RADARLINE: + if( mrModel.mnRadarStyle == XML_filled ) + eTypeId = TYPEID_RADARAREA; + break; + case TYPEID_SURFACE: + // create a deep 3D bar chart from surface charts + mrModel.mnGrouping = XML_standard; + break; + default:; + } + + // set the chart type info struct for the current chart type + maTypeInfo = lclGetTypeInfoFromTypeId( eTypeId ); +} + +TypeGroupConverter::~TypeGroupConverter() +{ +} + +bool TypeGroupConverter::isStacked() const +{ + return maTypeInfo.mbSupportsStacking && (mrModel.mnGrouping == XML_stacked); +} + +bool TypeGroupConverter::isPercent() const +{ + return maTypeInfo.mbSupportsStacking && (mrModel.mnGrouping == XML_percentStacked); +} + +bool TypeGroupConverter::is3dChart() const +{ + return mb3dChart; +} + +bool TypeGroupConverter::isWall3dChart() const +{ + return mb3dChart && (maTypeInfo.meTypeCategory != TYPECATEGORY_PIE); +} + +bool TypeGroupConverter::isDeep3dChart() const +{ + return isWall3dChart() && (mrModel.mnGrouping == XML_standard); +} + +bool TypeGroupConverter::isSeriesFrameFormat() const +{ + return mb3dChart || maTypeInfo.mbSeriesIsFrame2d; +} + +ObjectType TypeGroupConverter::getSeriesObjectType() const +{ + return mb3dChart ? OBJECTTYPE_FILLEDSERIES3D : + (maTypeInfo.mbSeriesIsFrame2d ? OBJECTTYPE_FILLEDSERIES2D : OBJECTTYPE_LINEARSERIES2D); +} + +bool TypeGroupConverter::isReverseSeries() const +{ + return maTypeInfo.mbReverseSeries && !mb3dChart && !isStacked() && !isPercent(); +} + +OUString TypeGroupConverter::getSingleSeriesTitle() const +{ + OUString aSeriesTitle; + if( !mrModel.maSeries.empty() && (maTypeInfo.mbSingleSeriesVis || (mrModel.maSeries.size() == 1)) ) + if( const TextModel* pText = mrModel.maSeries.front()->mxText.get() ) + if( const DataSequenceModel* pDataSeq = pText->mxDataSeq.get() ) + if( !pDataSeq->maData.empty() ) + pDataSeq->maData.begin()->second >>= aSeriesTitle; + return aSeriesTitle; +} + +Reference< XCoordinateSystem > TypeGroupConverter::createCoordinateSystem() +{ + // find service name for coordinate system + OUString aServiceName; + if( maTypeInfo.mbPolarCoordSystem ) + { + if( mb3dChart ) + aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.PolarCoordinateSystem3d" ); + else + aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.PolarCoordinateSystem2d" ); + } + else + { + if( mb3dChart ) + aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.CartesianCoordinateSystem3d" ); + else + aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.CartesianCoordinateSystem2d" ); + } + + // create the coordinate system object + Reference< XCoordinateSystem > xCoordSystem( createInstance( aServiceName ), UNO_QUERY ); + + // swap X and Y axis + if( maTypeInfo.mbSwappedAxesSet ) + { + PropertySet aPropSet( xCoordSystem ); + aPropSet.setProperty( PROP_SwapXAndYAxis, true ); + } + + return xCoordSystem; +} + +Reference< XLabeledDataSequence > TypeGroupConverter::createCategorySequence() +{ + Reference< XLabeledDataSequence > xLabeledSeq; + /* Find first existing category sequence. The bahaviour of Excel 2007 is + different to Excel 2003, which always used the category sequence of the + first series, even if it was empty. */ + for( TypeGroupModel::SeriesVector::iterator aIt = mrModel.maSeries.begin(), aEnd = mrModel.maSeries.end(); !xLabeledSeq.is() && (aIt != aEnd); ++aIt ) + { + if( (*aIt)->maSources.has( SeriesModel::CATEGORIES ) ) + { + SeriesConverter aSeriesConv( *this, **aIt ); + xLabeledSeq = aSeriesConv.createCategorySequence( CREATE_OUSTRING( "categories" ) ); + } + } + return xLabeledSeq; +} + +void TypeGroupConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, + const Reference< XCoordinateSystem >& rxCoordSystem, + sal_Int32 nAxesSetIdx, bool bSupportsVaryColorsByPoint ) +{ + try + { + // create the chart type object + OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName ); + Reference< XChartType > xChartType( createInstance( aService ), UNO_QUERY_THROW ); + + // additional properties + PropertySet aDiaProp( rxDiagram ); + PropertySet aTypeProp( xChartType ); + switch( maTypeInfo.meTypeCategory ) + { + case TYPECATEGORY_BAR: + { + Sequence< sal_Int32 > aInt32Seq( 2 ); + aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = mrModel.mnOverlap; + aTypeProp.setProperty( PROP_OverlapSequence, aInt32Seq ); + aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = mrModel.mnGapWidth; + aTypeProp.setProperty( PROP_GapwidthSequence, aInt32Seq ); + } + break; + case TYPECATEGORY_PIE: + { + aTypeProp.setProperty( PROP_UseRings, maTypeInfo.meTypeId == TYPEID_DOUGHNUT ); + /* #i85166# starting angle of first pie slice. 3D pie charts + use Y rotation setting in view3D element. Of-pie charts do + not support pie rotation. */ + if( !is3dChart() && (maTypeInfo.meTypeId != TYPEID_OFPIE) ) + convertPieRotation( aDiaProp, mrModel.mnFirstAngle ); + } + break; + default:; + } + + // create converter objects for all series models + typedef RefVector< SeriesConverter > SeriesConvVector; + SeriesConvVector aSeries; + for( TypeGroupModel::SeriesVector::iterator aIt = mrModel.maSeries.begin(), aEnd = mrModel.maSeries.end(); aIt != aEnd; ++aIt ) + aSeries.push_back( SeriesConvVector::value_type( new SeriesConverter( *this, **aIt ) ) ); + + // reverse series order for some unstacked 2D chart types + if( isReverseSeries() ) + ::std::reverse( aSeries.begin(), aSeries.end() ); + + // decide whether to use varying colors for each data point + bool bVaryColorsByPoint = bSupportsVaryColorsByPoint && mrModel.mbVaryColors; + switch( maTypeInfo.meVarPointMode ) + { + case VARPOINTMODE_NONE: bVaryColorsByPoint = false; break; + case VARPOINTMODE_SINGLE: bVaryColorsByPoint &= (mrModel.maSeries.size() == 1); break; + case VARPOINTMODE_MULTI: break; + } + + /* Stock chart needs special processing. Create one 'big' series with + data sequences of different roles. */ + if( maTypeInfo.meTypeId == TYPEID_STOCK ) + { + // create the data series object + Reference< XDataSeries > xDataSeries( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.DataSeries" ) ), UNO_QUERY ); + Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY ); + if( xDataSink.is() ) + { + // create a list of data sequences from all series + ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec; + OSL_ENSURE( aSeries.size() >= 3, "TypeGroupConverter::convertFromModel - too few stock chart series" ); + int nRoleIdx = (aSeries.size() == 3) ? 1 : 0; + for( SeriesConvVector::iterator aIt = aSeries.begin(), aEnd = aSeries.end(); (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt ) + { + // create a data sequence with a specific role + OUString aRole; + switch( nRoleIdx ) + { + case 0: aRole = CREATE_OUSTRING( "values-first" ); break; + case 1: aRole = CREATE_OUSTRING( "values-max" ); break; + case 2: aRole = CREATE_OUSTRING( "values-min" ); break; + case 3: aRole = CREATE_OUSTRING( "values-last" ); break; + } + Reference< XLabeledDataSequence > xDataSeq = (*aIt)->createValueSequence( aRole ); + if( xDataSeq.is() ) + aLabeledSeqVec.push_back( xDataSeq ); + } + + // attach labeled data sequences to series and insert series into chart type + xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) ); + + // formatting of high/low lines + aTypeProp.setProperty( PROP_ShowHighLow, true ); + PropertySet aSeriesProp( xDataSeries ); + if( mrModel.mxHiLowLines.is() ) + getFormatter().convertFrameFormatting( aSeriesProp, mrModel.mxHiLowLines, OBJECTTYPE_HILOLINE ); + else + // hi/low-lines cannot be switched off via "ShowHighLow" property (?) + aSeriesProp.setProperty( PROP_LineStyle, ::com::sun::star::drawing::LineStyle_NONE ); + + // formatting of up/down bars + bool bUpDownBars = mrModel.mxUpDownBars.is(); + aTypeProp.setProperty( PROP_Japanese, bUpDownBars ); + aTypeProp.setProperty( PROP_ShowFirst, bUpDownBars ); + if( bUpDownBars ) + { + UpDownBarsConverter aUpDownConv( *this, *mrModel.mxUpDownBars ); + aUpDownConv.convertFromModel( xChartType ); + } + + // insert the series into the chart type object + insertDataSeries( xChartType, xDataSeries, nAxesSetIdx ); + } + } + else + { + for( SeriesConvVector::iterator aIt = aSeries.begin(), aEnd = aSeries.end(); aIt != aEnd; ++aIt ) + { + SeriesConverter& rSeriesConv = **aIt; + Reference< XDataSeries > xDataSeries = rSeriesConv.createDataSeries( *this, bVaryColorsByPoint ); + insertDataSeries( xChartType, xDataSeries, nAxesSetIdx ); + + /* Excel does not use the value of the c:smooth element of the + chart type to set a default line smoothing for the data + series. Line smoothing is always controlled by the c:smooth + element of the respective data series. If the element in the + data series is missing, line smoothing is off, regardless of + the c:smooth element of the chart type. */ +#if !OOX_CHART_SMOOTHED_PER_SERIES + if( rSeriesConv.getModel().mbSmooth ) + convertLineSmooth( aTypeProp, true ); +#endif + } + } + + // add chart type object to coordinate system + Reference< XChartTypeContainer > xChartTypeCont( rxCoordSystem, UNO_QUERY_THROW ); + xChartTypeCont->addChartType( xChartType ); + + // set existence of bar connector lines at diagram (only in stacked 2D bar charts) + if( mrModel.mxSerLines.is() && !mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR) && (isStacked() || isPercent()) ) + aDiaProp.setProperty( PROP_ConnectBars, true ); + } + catch( Exception& ) + { + OSL_ENSURE( false, "TypeGroupConverter::convertFromModel - cannot add chart type" ); + } +} + +void TypeGroupConverter::convertMarker( PropertySet& rPropSet, sal_Int32 nOoxSymbol, sal_Int32 nOoxSize ) const +{ + if( !isSeriesFrameFormat() ) + { + namespace cssc = ::com::sun::star::chart2; + + // symbol style + cssc::Symbol aSymbol; + aSymbol.Style = cssc::SymbolStyle_STANDARD; + switch( nOoxSymbol ) + { + case XML_auto: aSymbol.Style = cssc::SymbolStyle_AUTO; break; + case XML_none: aSymbol.Style = cssc::SymbolStyle_NONE; break; + case XML_square: aSymbol.StandardSymbol = 0; break; // square + case XML_diamond: aSymbol.StandardSymbol = 1; break; // diamond + case XML_triangle: aSymbol.StandardSymbol = 3; break; // arrow up + case XML_x: aSymbol.StandardSymbol = 6; break; // bow tie + case XML_star: aSymbol.StandardSymbol = 7; break; // sand glass + case XML_dot: aSymbol.StandardSymbol = 4; break; // arrow right + case XML_dash: aSymbol.StandardSymbol = 2; break; // arrow down + case XML_circle: aSymbol.StandardSymbol = 4; break; // arrow right + case XML_plus: aSymbol.StandardSymbol = 5; break; // arrow left + } + + // symbol size (points in OOXML, 1/100 mm in Chart2) + sal_Int32 nSize = static_cast< sal_Int32 >( nOoxSize * (2540.0 / 72.0) + 0.5 ); + aSymbol.Size.Width = aSymbol.Size.Height = nSize; + + // set the property + rPropSet.setProperty( PROP_Symbol, aSymbol ); + } +} + +void TypeGroupConverter::convertLineSmooth( PropertySet& rPropSet, bool bOoxSmooth ) const +{ + if( !isSeriesFrameFormat() && (maTypeInfo.meTypeCategory != TYPECATEGORY_RADAR) ) + { + namespace cssc = ::com::sun::star::chart2; + cssc::CurveStyle eCurveStyle = bOoxSmooth ? cssc::CurveStyle_CUBIC_SPLINES : cssc::CurveStyle_LINES; + rPropSet.setProperty( PROP_CurveStyle, eCurveStyle ); + } +} + +void TypeGroupConverter::convertBarGeometry( PropertySet& rPropSet, sal_Int32 nOoxShape ) const +{ + if( mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR) ) + { + namespace cssc = ::com::sun::star::chart2; + + sal_Int32 nGeom3d = cssc::DataPointGeometry3D::CUBOID; + switch( nOoxShape ) + { + case XML_box: nGeom3d = cssc::DataPointGeometry3D::CUBOID; break; + case XML_cone: nGeom3d = cssc::DataPointGeometry3D::CONE; break; + case XML_coneToMax: nGeom3d = cssc::DataPointGeometry3D::CONE; break; + case XML_cylinder: nGeom3d = cssc::DataPointGeometry3D::CYLINDER; break; + case XML_pyramid: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break; + case XML_pyramidToMax: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break; + default: OSL_ENSURE( false, "TypeGroupConverter::convertBarGeometry - unknown 3D bar shape type" ); + } + rPropSet.setProperty( PROP_Geometry3D, nGeom3d ); + } +} + +void TypeGroupConverter::convertPieRotation( PropertySet& rPropSet, sal_Int32 nOoxAngle ) const +{ + if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE ) + { + // map OOXML [0,360] clockwise (0deg top) to Chart2 counterclockwise (0deg left) + sal_Int32 nAngle = (450 - nOoxAngle) % 360; + rPropSet.setProperty( PROP_StartingAngle, nAngle ); + } +} + +void TypeGroupConverter::convertPieExplosion( PropertySet& rPropSet, sal_Int32 nOoxExplosion ) const +{ + if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE ) + { + // pie explosion restricted to 100% in Chart2, set as double in range [0,1] + double fOffset = getLimitedValue< double >( nOoxExplosion / 100.0, 0.0, 1.0 ); + rPropSet.setProperty( PROP_Offset, fOffset ); + } +} + +// private -------------------------------------------------------------------- + +void TypeGroupConverter::insertDataSeries( const Reference< XChartType >& rxChartType, const Reference< XDataSeries >& rxSeries, sal_Int32 nAxesSetIdx ) +{ + if( rxSeries.is() ) + { + PropertySet aSeriesProp( rxSeries ); + + // series stacking mode + namespace cssc = ::com::sun::star::chart2; + cssc::StackingDirection eStacking = cssc::StackingDirection_NO_STACKING; + // stacked overrides deep-3d + if( isStacked() || isPercent() ) + eStacking = cssc::StackingDirection_Y_STACKING; + else if( isDeep3dChart() ) + eStacking = cssc::StackingDirection_Z_STACKING; + aSeriesProp.setProperty( PROP_StackingDirection, eStacking ); + + // additional series properties + aSeriesProp.setProperty( PROP_AttachedAxisIndex, nAxesSetIdx ); + + // insert series into container + try + { + Reference< XDataSeriesContainer > xSeriesCont( rxChartType, UNO_QUERY_THROW ); + xSeriesCont->addDataSeries( rxSeries ); + } + catch( Exception& ) + { + OSL_ENSURE( false, "TypeGroupConverter::insertDataSeries - cannot add data series" ); + } + } +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + diff --git a/oox/source/drawingml/chart/typegroupmodel.cxx b/oox/source/drawingml/chart/typegroupmodel.cxx new file mode 100644 index 000000000000..24f5420644e4 --- /dev/null +++ b/oox/source/drawingml/chart/typegroupmodel.cxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/drawingml/chart/typegroupmodel.hxx" + +namespace oox { +namespace drawingml { +namespace chart { + +// ============================================================================ + +UpDownBarsModel::UpDownBarsModel() : + mnGapWidth( 150 ) +{ +} + +UpDownBarsModel::~UpDownBarsModel() +{ +} + +// ============================================================================ + +TypeGroupModel::TypeGroupModel( sal_Int32 nTypeId ) : + mfSplitPos( 0.0 ), + mnBarDir( XML_col ), + mnBubbleScale( 100 ), + mnFirstAngle( 0 ), + mnGapDepth( 150 ), + mnGapWidth( 150 ), + mnGrouping( XML_standard ), + mnHoleSize( 10 ), + mnOfPieType( XML_pie ), + mnOverlap( 0 ), + mnRadarStyle( XML_standard ), + mnScatterStyle( XML_marker ), + mnSecondPieSize( 75 ), + mnShape( XML_box ), + mnSizeRepresents( XML_area ), + mnSplitType( XML_auto ), + mnTypeId( nTypeId ), + mbBubble3d( false ), + mbShowMarker( false ), + mbShowNegBubbles( false ), + mbSmooth( false ), + mbVaryColors( false ), + mbWireframe( false ) +{ +} + +TypeGroupModel::~TypeGroupModel() +{ +} + +// ============================================================================ + +} // namespace chart +} // namespace drawingml +} // namespace oox + |