diff options
Diffstat (limited to 'xmloff/source/chart/SchXMLChartContext.cxx')
-rw-r--r-- | xmloff/source/chart/SchXMLChartContext.cxx | 1248 |
1 files changed, 1248 insertions, 0 deletions
diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx new file mode 100644 index 000000000000..131b7a97e73e --- /dev/null +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -0,0 +1,1248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_xmloff.hxx" + +#include "SchXMLChartContext.hxx" +#include "SchXMLImport.hxx" +#include "SchXMLLegendContext.hxx" +#include "SchXMLPlotAreaContext.hxx" +#include "SchXMLParagraphContext.hxx" +#include "SchXMLTableContext.hxx" +#include "SchXMLSeriesHelper.hxx" +#include "SchXMLSeries2Context.hxx" +#include "SchXMLTools.hxx" +#include <comphelper/mediadescriptor.hxx> +#include <tools/debug.hxx> +// header for class ByteString +#include <tools/string.hxx> +#include "xmloff/xmlnmspe.hxx" +#include <xmloff/xmlement.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlstyle.hxx> +#include <xmloff/prstylei.hxx> + +#include "vector" +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/chart/XDiagram.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/util/XStringMapping.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/XVisualObject.hpp> + +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/data/XDataSink.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XTitled.hpp> + +using namespace com::sun::star; +using namespace ::xmloff::token; +using ::rtl::OUString; +using com::sun::star::uno::Reference; +using namespace ::SchXMLTools; + +namespace +{ + +void lcl_setRoleAtLabeledSequence( + const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq, + const ::rtl::OUString &rRole ) +{ + // set role of sequence + uno::Reference< chart2::data::XDataSequence > xValues( xLSeq->getValues()); + if( xValues.is()) + { + uno::Reference< beans::XPropertySet > xProp( xValues, uno::UNO_QUERY ); + if( xProp.is()) + xProp->setPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM( "Role" )), uno::makeAny( rRole )); + } +} + +void lcl_MoveDataToCandleStickSeries( + const uno::Reference< chart2::data::XDataSource > & xDataSource, + const uno::Reference< chart2::XDataSeries > & xDestination, + const OUString & rRole ) +{ + try + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( + xDataSource->getDataSequences()); + if( aLabeledSeq.getLength()) + { + lcl_setRoleAtLabeledSequence( aLabeledSeq[0], rRole ); + + // add to data series + uno::Reference< chart2::data::XDataSource > xSource( xDestination, uno::UNO_QUERY_THROW ); + // @todo: realloc only once outside this function + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences()); + aData.realloc( aData.getLength() + 1); + aData[ aData.getLength() - 1 ] = aLabeledSeq[0]; + uno::Reference< chart2::data::XDataSink > xSink( xDestination, uno::UNO_QUERY_THROW ); + xSink->setData( aData ); + } + } + catch( uno::Exception & ) + { + OSL_FAIL( "Exception caught while moving data to candlestick series" ); + } +} + +void lcl_setRoleAtFirstSequence( + const uno::Reference< chart2::XDataSeries > & xSeries, + const ::rtl::OUString & rRole ) +{ + uno::Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + if( aSeq.getLength()) + lcl_setRoleAtLabeledSequence( aSeq[0], rRole ); + } +} + +void lcl_removeEmptyChartTypeGroups( const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + if( ! xDoc.is()) + return; + + uno::Reference< chart2::XDiagram > xDia( xDoc->getFirstDiagram()); + if( ! xDia.is()) + return; + + try + { + // count all charttype groups to be able to leave at least one + sal_Int32 nRemainingGroups = 0; + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( sal_Int32 nI = aCooSysSeq.getLength(); nI--; ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW ); + nRemainingGroups += xCTCnt->getChartTypes().getLength(); + } + + // delete all empty groups, but leave at least group (empty or not) + for( sal_Int32 nI = aCooSysSeq.getLength(); nI-- && (nRemainingGroups > 1); ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); + for( sal_Int32 nJ=aCTSeq.getLength(); nJ-- && (nRemainingGroups > 1); ) + { + uno::Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nJ], uno::UNO_QUERY_THROW ); + if( xDSCnt->getDataSeries().getLength() == 0 ) + { + // note: iterator stays valid as we have a local sequence + xCTCnt->removeChartType( aCTSeq[nJ] ); + --nRemainingGroups; + } + } + } + } + catch( uno::Exception & ex ) + { + String aStr( ex.Message ); + ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US ); + OSL_TRACE( "Exception caught while removing empty chart types: %s", aBStr.GetBuffer()); + } +} + +uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const ::rtl::OUString& rStr, bool bAddOneToEachOldIndex ) +{ + const sal_Unicode aSpace( ' ' ); + + // count number of entries + ::std::vector< sal_Int32 > aVec; + sal_Int32 nLastPos = 0; + sal_Int32 nPos = 0; + while( nPos != -1 ) + { + nPos = rStr.indexOf( aSpace, nLastPos ); + if( nPos > nLastPos ) + { + aVec.push_back( rStr.copy( nLastPos, (nPos - nLastPos) ).toInt32() ); + } + if( nPos != -1 ) + nLastPos = nPos + 1; + } + // last entry + if( nLastPos != 0 && + rStr.getLength() > nLastPos ) + { + aVec.push_back( rStr.copy( nLastPos, (rStr.getLength() - nLastPos) ).toInt32() ); + } + + const sal_Int32 nVecSize = aVec.size(); + uno::Sequence< sal_Int32 > aSeq( nVecSize ); + + if(!bAddOneToEachOldIndex) + { + sal_Int32* pSeqArr = aSeq.getArray(); + for( nPos = 0; nPos < nVecSize; ++nPos ) + { + pSeqArr[ nPos ] = aVec[ nPos ]; + } + } + else if( bAddOneToEachOldIndex ) + { + aSeq.realloc( nVecSize+1 ); + aSeq[0]=0; + + sal_Int32* pSeqArr = aSeq.getArray(); + for( nPos = 0; nPos < nVecSize; ++nPos ) + { + pSeqArr[ nPos+1 ] = aVec[ nPos ]+1; + } + } + + return aSeq; +} + +} // anonymous namespace + +// ---------------------------------------- + +SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const rtl::OUString& rLocalName ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ), + m_bHasRangeAtPlotArea( false ), + m_bHasTableElement( false ), + mbAllRangeAddressesAvailable( sal_True ), + mbColHasLabels( sal_False ), + mbRowHasLabels( sal_False ), + meDataRowSource( chart::ChartDataRowSource_COLUMNS ), + mbIsStockChart( false ) +{ +} + +SchXMLChartContext::~SchXMLChartContext() +{} + +void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap(); + + uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY); + DBG_ASSERT(xVisualObject.is(),"need xVisualObject for page size"); + if( xVisualObject.is() ) + maChartSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); //#i103460# take the size given from the parent frame as default + + // this flag is necessarry for pie charts in the core + sal_Bool bSetSwitchData = sal_False; + + ::rtl::OUString sAutoStyleName; + ::rtl::OUString aOldChartTypeName; + bool bHasAddin = false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); + rtl::OUString aLocalName; + rtl::OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_CHART_HREF: + m_aXLinkHRefAttributeToIndicateDataProvider = aValue; + break; + + case XML_TOK_CHART_CLASS: + { + rtl::OUString sClassName; + sal_uInt16 nClassPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrName( + aValue, &sClassName ); + if( XML_NAMESPACE_CHART == nClassPrefix ) + { + SchXMLChartTypeEnum eChartTypeEnum = SchXMLTools::GetChartTypeEnum( sClassName ); + if( eChartTypeEnum != XML_CHART_CLASS_UNKNOWN ) + { + aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( sClassName, true /* bUseOldNames */ ); + maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( sClassName, false /* bUseOldNames */ ); + switch( eChartTypeEnum ) + { + case XML_CHART_CLASS_CIRCLE: + bSetSwitchData = sal_True; + break; + case XML_CHART_CLASS_STOCK: + mbIsStockChart = true; + break; + default: + break; + } + } + } + else if( XML_NAMESPACE_OOO == nClassPrefix ) + { + // service is taken from add-in-name attribute + bHasAddin = true; + + aOldChartTypeName = sClassName; + maChartTypeServiceName = sClassName; + } + } + break; + + case XML_TOK_CHART_WIDTH: + GetImport().GetMM100UnitConverter().convertMeasure( maChartSize.Width, aValue ); + break; + + case XML_TOK_CHART_HEIGHT: + GetImport().GetMM100UnitConverter().convertMeasure( maChartSize.Height, aValue ); + break; + + case XML_TOK_CHART_STYLE_NAME: + sAutoStyleName = aValue; + break; + + case XML_TOK_CHART_COL_MAPPING: + msColTrans = aValue; + break; + case XML_TOK_CHART_ROW_MAPPING: + msRowTrans = aValue; + break; + } + } + + if( aOldChartTypeName.getLength()<= 0 ) + { + OSL_FAIL( "need a charttype to create a diagram" ); + //set a fallback value: + ::rtl::OUString aChartClass_Bar( GetXMLToken(XML_BAR ) ); + aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, true /* bUseOldNames */ ); + maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, false /* bUseOldNames */ ); + } + + // Set the size of the draw page. + if( xVisualObject.is() ) + xVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, maChartSize ); + + InitChart( aOldChartTypeName, bSetSwitchData); + + if( bHasAddin ) + { + //correct charttype serveice name when having an addin + //and don't refresh addin during load + uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xDocProp.is() ) + { + try + { + xDocProp->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "BaseDiagram" ))) >>= aOldChartTypeName; + maChartTypeServiceName = SchXMLTools::GetNewChartTypeName( aOldChartTypeName ); + xDocProp->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "RefreshAddInAllowed" )) , uno::makeAny( sal_False) ); + } + catch( uno::Exception & ) + { + OSL_FAIL( "Exception during import SchXMLChartContext::StartElement" ); + } + } + } + + // set auto-styles for Area + uno::Reference< beans::XPropertySet > xProp( mrImportHelper.GetChartDocument()->getArea(), uno::UNO_QUERY ); + if( xProp.is()) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + mrImportHelper.GetChartFamilyID(), sAutoStyleName ); + + if( pStyle && pStyle->ISA( XMLPropStyleContext )) + (( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp ); + } + } +} + +namespace +{ + +struct NewDonutSeries +{ + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries > m_xSeries; + ::rtl::OUString msStyleName; + sal_Int32 mnAttachedAxis; + + ::std::vector< ::rtl::OUString > m_aSeriesStyles; + ::std::vector< ::rtl::OUString > m_aPointStyles; + + NewDonutSeries( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount ) + : m_xSeries( xSeries ) + , mnAttachedAxis( 1 ) + { + m_aPointStyles.resize(nPointCount); + m_aSeriesStyles.resize(nPointCount); + } + + void setSeriesStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex ) + { + DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()),"donut point <-> series count mismatch"); + if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) ) + m_aSeriesStyles[nPointIndex]=rStyleName; + } + + void setPointStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex ) + { + DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()),"donut point <-> series count mismatch"); + if( nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()) ) + m_aPointStyles[nPointIndex]=rStyleName; + } + + ::std::list< DataRowPointStyle > creatStyleList() + { + ::std::list< DataRowPointStyle > aRet; + + DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES + , m_xSeries, -1, 1, msStyleName, mnAttachedAxis ); + aRet.push_back( aSeriesStyle ); + + sal_Int32 nPointIndex=0; + ::std::vector< ::rtl::OUString >::iterator aPointIt( m_aPointStyles.begin() ); + ::std::vector< ::rtl::OUString >::iterator aPointEnd( m_aPointStyles.end() ); + while( aPointIt != aPointEnd ) + { + DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT + , m_xSeries, nPointIndex, 1, *aPointIt, mnAttachedAxis ); + if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) ) + { + aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex]; + } + if( aPointStyle.msSeriesStyleNameForDonuts.getLength() + || aPointStyle.msStyleName.getLength() ) + aRet.push_back( aPointStyle ); + ++aPointIt; + ++nPointIndex; + } + + return aRet; + } +}; + +void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::list< DataRowPointStyle >& rStyleList + , const ::std::map< ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries> , sal_Int32 >& rSeriesMap ) +{ + ::std::list< DataRowPointStyle >::iterator aIt(rStyleList.begin()); + ::std::list< DataRowPointStyle >::iterator aEnd(rStyleList.end()); + + //detect old series count + //and add old series to aSeriesMap + ::std::map< ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries >, sal_Int32 > aSeriesMap(rSeriesMap); + sal_Int32 nOldSeriesCount = 0; + { + sal_Int32 nMaxOldSeriesIndex = 0; + sal_Int32 nOldSeriesIndex = 0; + for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) + { + DataRowPointStyle aStyle(*aIt); + if(aStyle.meType == DataRowPointStyle::DATA_SERIES && + aStyle.m_xSeries.is() ) + { + nMaxOldSeriesIndex = nOldSeriesIndex; + + if( aSeriesMap.end() == aSeriesMap.find(aStyle.m_xSeries) ) + aSeriesMap[aStyle.m_xSeries] = nOldSeriesIndex; + + nOldSeriesIndex++; + } + } + nOldSeriesCount = nMaxOldSeriesIndex+1; + } + + + //initialize new series styles + ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapIt( aSeriesMap.begin() ); + ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapEnd( aSeriesMap.end() ); + + //sort by index + ::std::vector< NewDonutSeries > aNewSeriesVector; + { + ::std::map< sal_Int32, Reference< chart2::XDataSeries > > aIndexSeriesMap; + for( ; aSeriesMapIt != aSeriesMapEnd; ++aSeriesMapIt ) + aIndexSeriesMap[aSeriesMapIt->second] = aSeriesMapIt->first; + + ::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexIt( aIndexSeriesMap.begin() ); + ::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexEnd( aIndexSeriesMap.end() ); + + for( ; aIndexIt != aIndexEnd; ++aIndexIt ) + aNewSeriesVector.push_back( NewDonutSeries(aIndexIt->second,nOldSeriesCount) ); + } + + //overwrite attached axis information according to old series styles + for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) + { + DataRowPointStyle aStyle(*aIt); + if(aStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + aSeriesMapIt = aSeriesMap.find( aStyle.m_xSeries ); + if( aSeriesMapIt != aSeriesMapEnd && aSeriesMapIt->second < static_cast<sal_Int32>(aNewSeriesVector.size()) ) + aNewSeriesVector[aSeriesMapIt->second].mnAttachedAxis = aStyle.mnAttachedAxis; + } + } + + //overwrite new series style names with old series style name information + for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) + { + DataRowPointStyle aStyle(*aIt); + if( aStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); + if( aSeriesMapEnd != aSeriesMapIt ) + { + sal_Int32 nNewPointIndex = aSeriesMapIt->second; + + ::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() ); + ::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() ); + + for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt) + aNewSeriesIt->setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); + } + } + } + + //overwrite new series style names with point style name information + for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt ) + { + DataRowPointStyle aStyle(*aIt); + if( aStyle.meType == DataRowPointStyle::DATA_POINT ) + { + aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); + if( aSeriesMapEnd != aSeriesMapIt ) + { + sal_Int32 nNewPointIndex = aSeriesMapIt->second; + sal_Int32 nNewSeriesIndex = aStyle.m_nPointIndex; + sal_Int32 nRepeatCount = aStyle.m_nPointRepeat; + + while( nRepeatCount && (nNewSeriesIndex>=0) && (nNewSeriesIndex< static_cast<sal_Int32>(aNewSeriesVector.size()) ) ) + { + NewDonutSeries& rNewSeries( aNewSeriesVector[nNewSeriesIndex] ); + rNewSeries.setPointStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); + + nRepeatCount--; + nNewSeriesIndex++; + } + } + } + } + + //put information from aNewSeriesVector to output parameter rStyleList + rStyleList.clear(); + + ::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() ); + ::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() ); + for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt) + { + ::std::list< DataRowPointStyle > aList( aNewSeriesIt->creatStyleList() ); + rStyleList.insert(rStyleList.end(),aList.begin(),aList.end()); + } +} + +bool lcl_SpecialHandlingForDonutChartNeeded( + const ::rtl::OUString & rServiceName, + const SvXMLImport & rImport ) +{ + bool bResult = false; + if( rServiceName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.DonutChartType" ))) + { + bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() ); + } + return bResult; +} + +} // anonymous namespace + + +void lcl_ApplyDataFromRectangularRangeToDiagram( + const uno::Reference< chart2::XChartDocument >& xNewDoc + , const rtl::OUString& rRectangularRange + , ::com::sun::star::chart::ChartDataRowSource eDataRowSource + , bool bRowHasLabels, bool bColHasLabels + , bool bSwitchOnLabelsAndCategoriesForOwnData + , const rtl::OUString& sColTrans + , const rtl::OUString& sRowTrans ) +{ + if( !xNewDoc.is() ) + return; + + uno::Reference< chart2::XDiagram > xNewDia( xNewDoc->getFirstDiagram()); + uno::Reference< chart2::data::XDataProvider > xDataProvider( xNewDoc->getDataProvider() ); + if( !xNewDia.is() || !xDataProvider.is() ) + return; + + sal_Bool bFirstCellAsLabel = + (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels; + sal_Bool bHasCateories = + (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels; + + if( bSwitchOnLabelsAndCategoriesForOwnData ) + { + bFirstCellAsLabel = true; + bHasCateories = true; + } + + uno::Sequence< beans::PropertyValue > aArgs( 3 ); + aArgs[0] = beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "CellRangeRepresentation" )), + -1, uno::makeAny( rRectangularRange ), + beans::PropertyState_DIRECT_VALUE ); + aArgs[1] = beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "DataRowSource" )), + -1, uno::makeAny( eDataRowSource ), + beans::PropertyState_DIRECT_VALUE ); + aArgs[2] = beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "FirstCellAsLabel" )), + -1, uno::makeAny( bFirstCellAsLabel ), + beans::PropertyState_DIRECT_VALUE ); + + if( sColTrans.getLength() || sRowTrans.getLength() ) + { + aArgs.realloc( aArgs.getLength() + 1 ); + aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "SequenceMapping" )), + -1, uno::makeAny( sColTrans.getLength() + ? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) + : lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ), + beans::PropertyState_DIRECT_VALUE ); + } + + //work around wrong writer ranges ( see Issue 58464 ) + { + rtl::OUString aChartOleObjectName; + uno::Reference< frame::XModel > xModel(xNewDoc, uno::UNO_QUERY ); + if( xModel.is() ) + { + comphelper::MediaDescriptor aMediaDescriptor( xModel->getArgs() ); + + comphelper::MediaDescriptor::const_iterator aIt( + aMediaDescriptor.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HierarchicalDocumentName" )))); + if( aIt != aMediaDescriptor.end() ) + { + aChartOleObjectName = (*aIt).second.get< ::rtl::OUString >(); + } + } + if( aChartOleObjectName.getLength() ) + { + aArgs.realloc( aArgs.getLength() + 1 ); + aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ChartOleObjectName" )), + -1, uno::makeAny( aChartOleObjectName ), + beans::PropertyState_DIRECT_VALUE ); + } + } + + + uno::Reference< chart2::data::XDataSource > xDataSource( + xDataProvider->createDataSource( aArgs )); + + aArgs.realloc( aArgs.getLength() + 2 ); + aArgs[ aArgs.getLength() - 2 ] = beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "HasCategories" )), + -1, uno::makeAny( bHasCateories ), + beans::PropertyState_DIRECT_VALUE ); + aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue( + ::rtl::OUString::createFromAscii("UseCategoriesAsX"), + -1, uno::makeAny( sal_False ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui) + beans::PropertyState_DIRECT_VALUE ); + + xNewDia->setDiagramData( xDataSource, aArgs ); +} + +void SchXMLChartContext::EndElement() +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); + uno::Reference< chart2::XChartDocument > xNewDoc( xDoc, uno::UNO_QUERY ); + + if( xProp.is()) + { + if( maMainTitle.getLength()) + { + uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + try + { + uno::Any aAny; + aAny <<= maMainTitle; + xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny ); + } + catch( beans::UnknownPropertyException ) + { + OSL_FAIL( "Property String for Title not available" ); + } + } + } + if( maSubTitle.getLength()) + { + uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + try + { + uno::Any aAny; + aAny <<= maSubTitle; + xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny ); + } + catch( beans::UnknownPropertyException ) + { + OSL_FAIL( "Property String for Title not available" ); + } + } + } + } + + // cleanup: remove empty chart type groups + lcl_removeEmptyChartTypeGroups( xNewDoc ); + + // set stack mode before a potential chart type detection (in case we have a rectangular range) + uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() ); + uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY ); + if( xDiaProp.is()) + { + if( maSeriesDefaultsAndStyles.maStackedDefault.hasValue()) + xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Stacked")),maSeriesDefaultsAndStyles.maStackedDefault); + if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue()) + xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Percent")),maSeriesDefaultsAndStyles.maPercentDefault); + if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue()) + xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Deep")),maSeriesDefaultsAndStyles.maDeepDefault); + if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue()) + xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StackedBarsConnected")),maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault); + } + + //the OOo 2.0 implementation and older has a bug with donuts + bool bSpecialHandlingForDonutChart = lcl_SpecialHandlingForDonutChartNeeded( + maChartTypeServiceName, GetImport()); + + // apply data + if(!xNewDoc.is()) + return; + + bool bHasOwnData = false; + if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "." ) ) ) //data comes from the chart itself + bHasOwnData = true; + else if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ".." ) ) ) //data comes from the parent application + bHasOwnData = false; + else if( m_aXLinkHRefAttributeToIndicateDataProvider.getLength() ) //not supported so far to get the data by sibling objects -> fall back to chart itself if data are available + bHasOwnData = m_bHasTableElement; + else + bHasOwnData = !m_bHasRangeAtPlotArea; + + if( xNewDoc->hasInternalDataProvider()) + { + if( !m_bHasTableElement && !m_aXLinkHRefAttributeToIndicateDataProvider.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "." ) ) ) + { + //#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area + bool bSwitchSuccessful = SchXMLTools::switchBackToDataProviderFromParent( xNewDoc, maLSequencesPerIndex ); + bHasOwnData = !bSwitchSuccessful; + } + else + bHasOwnData = true;//e.g. in case of copy->paste from calc to impress + } + else if( bHasOwnData ) + { + xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ ); + } + if( bHasOwnData ) + msChartAddress = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "all" )); + + bool bSwitchRangesFromOuterToInternalIfNecessary = false; + if( !bHasOwnData && mbAllRangeAddressesAvailable ) + { + // special handling for stock chart (merge series together) + if( mbIsStockChart ) + MergeSeriesForStockChart(); + } + else if( msChartAddress.getLength() ) + { + //own data or only rectangular range available + + if( xNewDoc->hasInternalDataProvider() ) + SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); + + bool bOlderThan2_3 = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( Reference< frame::XModel >( xNewDoc, uno::UNO_QUERY )); + bool bOldFileWithOwnDataFromRows = (bOlderThan2_3 && bHasOwnData && (meDataRowSource==chart::ChartDataRowSource_ROWS)); // in this case there are range addresses that are simply wrong. + + if( mbAllRangeAddressesAvailable && !bSpecialHandlingForDonutChart && !mbIsStockChart && + !bOldFileWithOwnDataFromRows ) + { + //bHasOwnData is true in this case! + //e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress) + bSwitchRangesFromOuterToInternalIfNecessary = true; + } + else + { + //apply data from rectangular range + + // create datasource from data provider with rectangular range parameters and change the diagram setDiagramData + try + { + if( bOlderThan2_3 && xDiaProp.is() )//for older charts the hidden cells were removed by calc on the fly + xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IncludeHiddenCells")),uno::makeAny(false)); + + // note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions", + // (analogously mbColHasLabels means we have "row-descriptions") + lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); + } + catch( uno::Exception & ) + { + //try to fallback to internal data + OSL_FAIL( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" ); + if(!bHasOwnData) + { + bHasOwnData = true; + msChartAddress = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "all" )); + if( !xNewDoc->hasInternalDataProvider() ) + { + xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ ); + SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); + try + { + lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); + } + catch( uno::Exception & ) + { + OSL_FAIL( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" ); + } + } + } + } + } + } + else + { + OSL_FAIL( " Must not get here" ); + } + + // now all series and data point properties are available and can be set + { + if( bSpecialHandlingForDonutChart ) + { + uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() ); + lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles.maSeriesStyleList + , SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram) ); + } + + SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles, uno::Reference< frame::XModel >(xDoc, uno::UNO_QUERY ) ); + + //set defaults from diagram to the new series: + //check whether we need to remove lines from symbol only charts + bool bSwitchOffLinesForScatter = false; + { + bool bLinesOn = true; + if( (maSeriesDefaultsAndStyles.maLinesOnProperty >>= bLinesOn) && !bLinesOn ) + { + if( 0 == maChartTypeServiceName.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.ScatterChartType" ) ) ) + { + bSwitchOffLinesForScatter = true; + SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleList ); + } + } + } + SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles ); + + // set autostyles for series and data points + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = NULL; + ::rtl::OUString sCurrStyleName; + + if( pStylesCtxt ) + { + //iterate over data-series first + //don't set series styles for donut charts + if( !bSpecialHandlingForDonutChart ) + { + SchXMLSeries2Context::setStylesToSeries( maSeriesDefaultsAndStyles + , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, maLSequencesPerIndex ); + // ... then set attributes for statistics (after their existence was set in the series) + SchXMLSeries2Context::setStylesToStatisticsObjects( maSeriesDefaultsAndStyles + , pStylesCtxt, pStyle, sCurrStyleName ); + } + } + + //#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost + if( bSwitchRangesFromOuterToInternalIfNecessary ) + { + if( xNewDoc->hasInternalDataProvider() ) + SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable, maLSequencesPerIndex, xNewDoc, meDataRowSource ); + } + + if( pStylesCtxt ) + { + // ... then iterate over data-point attributes, so the latter are not overwritten + SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles + , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, bSpecialHandlingForDonutChart, bSwitchOffLinesForScatter ); + } + } + + if( xProp.is()) + xProp->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "RefreshAddInAllowed" )) , uno::makeAny( sal_True) ); +} + +void SchXMLChartContext::MergeSeriesForStockChart() +{ + OSL_ASSERT( mbIsStockChart ); + try + { + uno::Reference< chart::XChartDocument > xOldDoc( mrImportHelper.GetChartDocument()); + uno::Reference< chart2::XChartDocument > xDoc( xOldDoc, uno::UNO_QUERY_THROW ); + uno::Reference< chart2::XDiagram > xDiagram( xDoc->getFirstDiagram()); + if( ! xDiagram.is()) + return; + + bool bHasJapaneseCandlestick = true; + uno::Reference< chart2::XDataSeriesContainer > xDSContainer; + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx ) + { + if( aChartTypes[nCTIdx]->getChartType().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.CandleStickChartType"))) + { + xDSContainer.set( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xCTProp( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW ); + xCTProp->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Japanese" ))) >>= bHasJapaneseCandlestick; + break; + } + } + } + + if( xDSContainer.is()) + { + // with japanese candlesticks: open, low, high, close + // otherwise: low, high, close + uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSContainer->getDataSeries()); + const sal_Int32 nSeriesCount( aSeriesSeq.getLength()); + const sal_Int32 nSeriesPerCandleStick = bHasJapaneseCandlestick ? 4: 3; + sal_Int32 nCandleStickCount = nSeriesCount / nSeriesPerCandleStick; + OSL_ASSERT( nSeriesPerCandleStick * nCandleStickCount == nSeriesCount ); + uno::Sequence< uno::Reference< chart2::XDataSeries > > aNewSeries( nCandleStickCount ); + for( sal_Int32 i=0; i<nCandleStickCount; ++i ) + { + sal_Int32 nSeriesIndex = i*nSeriesPerCandleStick; + if( bHasJapaneseCandlestick ) + { + // open values + lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString(RTL_CONSTASCII_USTRINGPARAM( "values-first" ))); + aNewSeries[i] = aSeriesSeq[ nSeriesIndex ]; + // low values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], OUString(RTL_CONSTASCII_USTRINGPARAM( "values-min" ))); + } + else + { + // low values + lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString(RTL_CONSTASCII_USTRINGPARAM( "values-min" ))); + aNewSeries[i] = aSeriesSeq[ nSeriesIndex ]; + } + // high values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], OUString(RTL_CONSTASCII_USTRINGPARAM( "values-max" ))); + // close values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], OUString(RTL_CONSTASCII_USTRINGPARAM( "values-last" ))); + } + xDSContainer->setDataSeries( aNewSeries ); + } + } + catch( uno::Exception & ) + { + OSL_FAIL( "Exception while merging series for stock chart" ); + } +} + +SvXMLImportContext* SchXMLChartContext::CreateChildContext( + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + static const sal_Bool bTrue = sal_True; + static const uno::Any aTrueBool( &bTrue, ::getBooleanCppuType()); + + SvXMLImportContext* pContext = 0; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetChartElemTokenMap(); + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_CHART_PLOT_AREA: + pContext = new SchXMLPlotAreaContext( mrImportHelper, GetImport(), rLocalName, + m_aXLinkHRefAttributeToIndicateDataProvider, + maSeriesAddresses, msCategoriesAddress, + msChartAddress, m_bHasRangeAtPlotArea, mbAllRangeAddressesAvailable, + mbColHasLabels, mbRowHasLabels, + meDataRowSource, + maSeriesDefaultsAndStyles, + maChartTypeServiceName, + maLSequencesPerIndex, maChartSize ); + break; + + case XML_TOK_CHART_TITLE: + if( xDoc.is()) + { + if( xProp.is()) + { + xProp->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "HasMainTitle" )), aTrueBool ); + } + uno::Reference< drawing::XShape > xTitleShape( xDoc->getTitle(), uno::UNO_QUERY ); + pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), + rLocalName, maMainTitle, xTitleShape ); + } + break; + + case XML_TOK_CHART_SUBTITLE: + if( xDoc.is()) + { + if( xProp.is()) + { + xProp->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "HasSubTitle" )), aTrueBool ); + } + uno::Reference< drawing::XShape > xTitleShape( xDoc->getSubTitle(), uno::UNO_QUERY ); + pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), + rLocalName, maSubTitle, xTitleShape ); + } + break; + + case XML_TOK_CHART_LEGEND: + pContext = new SchXMLLegendContext( mrImportHelper, GetImport(), rLocalName ); + break; + + case XML_TOK_CHART_TABLE: + { + SchXMLTableContext * pTableContext = + new SchXMLTableContext( mrImportHelper, GetImport(), rLocalName, maTable ); + m_bHasTableElement = true; + // #i85913# take into account column- and row- mapping for + // charts with own data only for those which were not copied + // from a place where they got data from the container. Note, + // that this requires the plot-area been read before the table + // (which is required in the ODF spec) + // Note: For stock charts and donut charts with special handling + // the mapping must not be applied! + if( !msChartAddress.getLength() && !mbIsStockChart && + !lcl_SpecialHandlingForDonutChartNeeded( + maChartTypeServiceName, GetImport())) + { + if( msColTrans.getLength() > 0 ) + { + OSL_ASSERT( msRowTrans.getLength() == 0 ); + pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true )); + msColTrans = OUString(); + } + else if( msRowTrans.getLength() > 0 ) + { + pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true )); + msRowTrans = OUString(); + } + } + pContext = pTableContext; + } + break; + + default: + // try importing as an additional shape + if( ! mxDrawPage.is()) + { + uno::Reference< drawing::XDrawPageSupplier > xSupp( xDoc, uno::UNO_QUERY ); + if( xSupp.is()) + mxDrawPage = uno::Reference< drawing::XShapes >( xSupp->getDrawPage(), uno::UNO_QUERY ); + + DBG_ASSERT( mxDrawPage.is(), "Invalid Chart Page" ); + } + if( mxDrawPage.is()) + pContext = GetImport().GetShapeImport()->CreateGroupChildContext( + GetImport(), nPrefix, rLocalName, xAttrList, mxDrawPage ); + break; + } + + if( ! pContext ) + pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); + + return pContext; +} + + +/* + With a locked controller the following is done here: + 1. Hide title, subtitle, and legend. + 2. Set the size of the draw page. + 3. Set a (logically) empty data set. + 4. Set the chart type. +*/ +void SchXMLChartContext::InitChart( + const OUString & rChartTypeServiceName, // currently the old service name + sal_Bool /* bSetSwitchData */ ) +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + DBG_ASSERT( xDoc.is(), "No valid document!" ); + uno::Reference< frame::XModel > xModel (xDoc, uno::UNO_QUERY ); + + // Remove Title and Diagram ("De-InitNew") + uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xNewDoc.is()) + { + xNewDoc->setFirstDiagram( 0 ); + uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY ); + if( xTitled.is()) + xTitled->setTitleObject( 0 ); + } + + // Set the chart type via setting the diagram. + if( rChartTypeServiceName.getLength() && + xDoc.is()) + { + uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY ); + if( xFact.is()) + { + uno::Reference< chart::XDiagram > xDia( xFact->createInstance( rChartTypeServiceName ), uno::UNO_QUERY ); + if( xDia.is()) + xDoc->setDiagram( xDia ); + } + } +} + +// ---------------------------------------- + +SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, + const rtl::OUString& rLocalName, + rtl::OUString& rTitle, + uno::Reference< drawing::XShape >& xTitleShape ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ), + mrTitle( rTitle ), + mxTitleShape( xTitleShape ) +{ +} + +SchXMLTitleContext::~SchXMLTitleContext() +{} + +void SchXMLTitleContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + + com::sun::star::awt::Point maPosition; + bool bHasXPosition=false; + bool bHasYPosition=false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); + rtl::OUString aLocalName; + rtl::OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_SVG ) + { + if( IsXMLToken( aLocalName, XML_X ) ) + { + GetImport().GetMM100UnitConverter().convertMeasure( maPosition.X, aValue ); + bHasXPosition = true; + } + else if( IsXMLToken( aLocalName, XML_Y ) ) + { + GetImport().GetMM100UnitConverter().convertMeasure( maPosition.Y, aValue ); + bHasYPosition = true; + } + } + else if( nPrefix == XML_NAMESPACE_CHART ) + { + if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + msAutoStyleName = aValue; + } + } + + + if( mxTitleShape.is()) + { + if( bHasXPosition && bHasYPosition ) + mxTitleShape->setPosition( maPosition ); + + uno::Reference< beans::XPropertySet > xProp( mxTitleShape, uno::UNO_QUERY ); + if( xProp.is()) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + mrImportHelper.GetChartFamilyID(), msAutoStyleName ); + + if( pStyle && pStyle->ISA( XMLPropStyleContext )) + (( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp ); + } + } + } +} + +SvXMLImportContext* SchXMLTitleContext::CreateChildContext( + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = 0; + + if( nPrefix == XML_NAMESPACE_TEXT && + IsXMLToken( rLocalName, XML_P ) ) + { + pContext = new SchXMLParagraphContext( GetImport(), rLocalName, mrTitle ); + } + else + pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); + + return pContext; +} + +// ---------------------------------------- + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |