diff options
Diffstat (limited to 'xmloff/source/chart/SchXMLExport.cxx')
-rw-r--r-- | xmloff/source/chart/SchXMLExport.cxx | 4037 |
1 files changed, 4037 insertions, 0 deletions
diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx new file mode 100644 index 000000000000..e6f6fc6d9340 --- /dev/null +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -0,0 +1,4037 @@ +/************************************************************************* + * + * 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 <xmloff/xmlprmap.hxx> + +#include "SchXMLExport.hxx" +#include "XMLChartPropertySetMapper.hxx" +#include "SchXMLSeriesHelper.hxx" +#include "ColorPropertySet.hxx" +#include "SchXMLTools.hxx" +#include <tools/debug.hxx> +#include <rtl/logfile.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/globname.hxx> +#include <sot/clsids.hxx> + +#include <xmloff/nmspmap.hxx> +#include "xmlnmspe.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/families.hxx> +#include <xmloff/xmlaustp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlmetae.hxx> +#include "xexptran.hxx" +#include <rtl/math.hxx> +// header for any2enum +#include <comphelper/extract.hxx> + +#include <list> +#include <typeinfo> +#include <algorithm> + +#include <com/sun/star/task/XStatusIndicatorSupplier.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XRefreshable.hpp> + +#include <com/sun/star/chart/XChartDocument.hpp> +#include <com/sun/star/chart/ChartLegendPosition.hpp> +#include <com/sun/star/chart/XTwoAxisXSupplier.hpp> +#include <com/sun/star/chart/XTwoAxisYSupplier.hpp> +#include <com/sun/star/chart/XAxisZSupplier.hpp> +#include <com/sun/star/chart/XComplexDescriptionAccess.hpp> +#include <com/sun/star/chart/ChartDataRowSource.hpp> +#include <com/sun/star/chart/ChartAxisAssign.hpp> +#include <com/sun/star/chart/ChartSeriesAddress.hpp> +#include <com/sun/star/chart/X3DDisplay.hpp> +#include <com/sun/star/chart/XStatisticDisplay.hpp> +#include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp> +#include <com/sun/star/chart/XDiagramPositioning.hpp> + +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/XDiagram.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XRegressionCurveContainer.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <com/sun/star/chart2/data/XDataSource.hpp> +#include <com/sun/star/chart2/data/XDataSink.hpp> +#include <com/sun/star/chart2/data/XDataReceiver.hpp> +#include <com/sun/star/chart2/data/XDataProvider.hpp> +#include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp> +#include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> +#include <com/sun/star/chart2/data/XTextualDataSequence.hpp> +#include <com/sun/star/chart2/data/XNumericalDataSequence.hpp> + +#include <com/sun/star/util/XStringMapping.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/XVisualObject.hpp> +#include <com/sun/star/container/XChild.hpp> + + +#include "MultiPropertySetHandler.hxx" +#include "PropertyMap.hxx" + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::rtl::OUStringToOString; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::std::vector; + +// ======================================== +// class SchXMLExportHelper_Impl +// ======================================== + +class SchXMLExportHelper_Impl +{ +public: + // first: data sequence for label, second: data sequence for values. + typedef ::std::pair< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence >, + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence > > tLabelValuesDataPair; + typedef ::std::vector< tLabelValuesDataPair > tDataSequenceCont; + +public: + SchXMLExportHelper_Impl( SvXMLExport& rExport, + SvXMLAutoStylePoolP& rASPool ); + + virtual ~SchXMLExportHelper_Impl(); + + // auto-styles + /// parse chart and collect all auto-styles used in current pool + void collectAutoStyles( com::sun::star::uno::Reference< + com::sun::star::chart::XChartDocument > rChartDoc ); + + /// write the styles collected into the current pool as <style:style> elements + void exportAutoStyles(); + + /** export the <chart:chart> element corresponding to rChartDoc + if bIncludeTable is true, the chart data is exported as <table:table> + element (inside the chart element). + + Otherwise the external references stored in the chart document are used + for writing the corresponding attributes at series + + All attributes contained in xAttrList are written at the chart element, + which ist the outer element of a chart. So these attributes can easily + be parsed again by the container + */ + void exportChart( com::sun::star::uno::Reference< + com::sun::star::chart::XChartDocument > rChartDoc, + sal_Bool bIncludeTable ); + + UniReference< XMLPropertySetMapper > GetPropertySetMapper() const; + + void SetChartRangeAddress( const ::rtl::OUString& rAddress ) + { msChartAddress = rAddress; } + void SetTableNumberList( const ::rtl::OUString& rList ) + { msTableNumberList = rList; } + + void InitRangeSegmentationProperties( + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XChartDocument > & xChartDoc ); + + ::com::sun::star::awt::Size getPageSize( + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XChartDocument > & xChartDoc ) const; + + /** first parseDocument: collect autostyles and store names in this queue + second parseDocument: export content and use names from this queue + */ + ::std::queue< ::rtl::OUString > maAutoStyleNameQueue; + void CollectAutoStyle( + const std::vector< XMLPropertyState >& aStates ); + void AddAutoStyleAttribute( + const std::vector< XMLPropertyState >& aStates ); + + SvXMLAutoStylePoolP& GetAutoStylePoolP() + { return mrAutoStylePool; } + + /// if bExportContent is false the auto-styles are collected + void parseDocument( com::sun::star::uno::Reference< + com::sun::star::chart::XChartDocument >& rChartDoc, + sal_Bool bExportContent, + sal_Bool bIncludeTable = sal_False ); + void exportTable(); + void exportPlotArea( + com::sun::star::uno::Reference< com::sun::star::chart::XDiagram > xDiagram, + com::sun::star::uno::Reference< com::sun::star::chart2::XDiagram > xNewDiagram, + const ::com::sun::star::awt::Size & rPageSize, + sal_Bool bExportContent, + sal_Bool bIncludeTable ); + void exportCoordinateRegion( const com::sun::star::uno::Reference< com::sun::star::chart::XDiagram >& xDiagram ); + void exportAxes( const com::sun::star::uno::Reference< com::sun::star::chart::XDiagram > & xDiagram, + const com::sun::star::uno::Reference< com::sun::star::chart2::XDiagram > & xNewDiagram, + sal_Bool bExportContent ); + + void exportSeries( + const com::sun::star::uno::Reference< com::sun::star::chart2::XDiagram > & xNewDiagram, + const ::com::sun::star::awt::Size & rPageSize, + sal_Bool bExportContent, + sal_Bool bHasTwoYAxes ); + void exportCandleStickSeries( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries > > & aSeriesSeq, + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDiagram > & xDiagram, + sal_Bool bJapaneseCandleSticks, + sal_Bool bExportContent ); + void exportDataPoints( + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > & xSeriesProperties, + sal_Int32 nSeriesLength, + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDiagram > & xDiagram, + sal_Bool bExportContent ); + void exportRegressionCurve( + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries > & xSeries, + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > & xSeriesProp, + const ::com::sun::star::awt::Size & rPageSize, + sal_Bool bExportContent ); + + /// add svg position as attribute for current element + void addPosition( const ::com::sun::star::awt::Point & rPosition ); + void addPosition( com::sun::star::uno::Reference< com::sun::star::drawing::XShape > xShape ); + /// add svg size as attribute for current element + void addSize( const ::com::sun::star::awt::Size & rSize ); + void addSize( com::sun::star::uno::Reference< com::sun::star::drawing::XShape > xShape ); + /// fills the member msString with the appropriate String (i.e. "A3") + void getCellAddress( sal_Int32 nCol, sal_Int32 nRow ); + /// exports a string as a paragraph element + void exportText( const ::rtl::OUString& rText, bool bConvertTabsLFs = false ); + void exportErrorBarRanges(); + + SchXMLExportHelper_Impl(SchXMLExportHelper_Impl &); // not defined + void operator =(SchXMLExportHelper_Impl &); // not defined + +public: + SvXMLExport& mrExport; + SvXMLAutoStylePoolP& mrAutoStylePool; + UniReference< XMLPropertyHandlerFactory > mxPropertyHandlerFactory; + UniReference< XMLPropertySetMapper > mxPropertySetMapper; + UniReference< XMLChartExportPropertyMapper > mxExpPropMapper; + + rtl::OUString msTableName; + rtl::OUStringBuffer msStringBuffer; + rtl::OUString msString; + + // members filled by InitRangeSegmentationProperties (retrieved from DataProvider) + sal_Bool mbHasSeriesLabels; + sal_Bool mbHasCategoryLabels; //if the categories are only automatically generated this will be false + sal_Bool mbRowSourceColumns; + rtl::OUString msChartAddress; + rtl::OUString msTableNumberList; + ::com::sun::star::uno::Sequence< sal_Int32 > maSequenceMapping; + + rtl::OUString msCLSID; + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > mxAdditionalShapes; + + tDataSequenceCont m_aDataSequencesToExport; + rtl::OUString maCategoriesRange; +}; + +namespace +{ +Reference< uno::XComponentContext > lcl_getComponentContext() +{ + Reference< uno::XComponentContext > xContext; + try + { + Reference< beans::XPropertySet > xFactProp( comphelper::getProcessServiceFactory(), uno::UNO_QUERY ); + if( xFactProp.is()) + xFactProp->getPropertyValue(OUString::createFromAscii("DefaultContext")) >>= xContext; + } + catch( uno::Exception& ) + {} + + return xContext; +} + +class lcl_MatchesRole : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool > +{ +public: + explicit lcl_MatchesRole( const OUString & aRole ) : + m_aRole( aRole ) + {} + + bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const + { + if( !xSeq.is() ) + return false; + Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY ); + OUString aRole; + + return ( xProp.is() && + (xProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" )) ) >>= aRole ) && + m_aRole.equals( aRole )); + } + +private: + OUString m_aRole; +}; + +template< typename T > + void lcl_SequenceToVectorAppend( const Sequence< T > & rSource, ::std::vector< T > & rDestination ) +{ + rDestination.reserve( rDestination.size() + rSource.getLength()); + ::std::copy( rSource.getConstArray(), rSource.getConstArray() + rSource.getLength(), + ::std::back_inserter( rDestination )); +} + +template< typename T > + void lcl_SequenceToVector( const Sequence< T > & rSource, ::std::vector< T > & rDestination ) +{ + rDestination.clear(); + lcl_SequenceToVectorAppend( rSource, rDestination ); +} + +Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram ) +{ + Reference< chart2::data::XLabeledDataSequence > xResult; + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDiagram, uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i ) + { + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[i] ); + OSL_ASSERT( xCooSys.is()); + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI) + { + Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.Categories.is()) + { + xResult.set( aScaleData.Categories ); + break; + } + } + } + } + } + } + catch( uno::Exception & ex ) + { + (void)ex; // avoid warning for pro build + OSL_ENSURE( false, OUStringToOString( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught. Type: " )) + + OUString::createFromAscii( typeid( ex ).name()) + + OUString( RTL_CONSTASCII_USTRINGPARAM( ", Message: " )) + + ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); + } + + return xResult; +} + +Reference< chart2::data::XDataSource > lcl_createDataSource( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData ) +{ + Reference< chart2::data::XDataSink > xSink; + Reference< uno::XComponentContext > xContext( lcl_getComponentContext()); + if( xContext.is() ) + xSink.set( + xContext->getServiceManager()->createInstanceWithContext( + OUString::createFromAscii("com.sun.star.chart2.data.DataSource"), + xContext ), uno::UNO_QUERY_THROW ); + if( xSink.is()) + xSink->setData( aData ); + + return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY ); +} + +Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer; + if( xChartDoc.is() ) + { + Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram()); + ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram )); + for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aSeriesIt( aSeriesVector.begin() ) + ; aSeriesIt != aSeriesVector.end(); ++aSeriesIt ) + { + Reference< chart2::data::XDataSource > xDataSource( *aSeriesIt, uno::UNO_QUERY ); + if( !xDataSource.is() ) + continue; + uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() ); + lcl_SequenceToVectorAppend( aDataSequences, aContainer ); + } + } + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aRet( aContainer.size()); + ::std::copy( aContainer.begin(), aContainer.end(), aRet.getArray()); + + return aRet; +} + +Reference< chart2::data::XLabeledDataSequence > + lcl_getDataSequenceByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq, + const OUString & rRole ) +{ + Reference< chart2::data::XLabeledDataSequence > aNoResult; + + const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray(); + const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength(); + const Reference< chart2::data::XLabeledDataSequence > * pMatch = + ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole )); + + if( pMatch != pEnd ) + return *pMatch; + + return aNoResult; +} + +Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, sal_Bool& rOutSourceHasCategoryLabels ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector; + + //categories are always the first sequence + Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram()); + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) ); + if( xCategories.is() ) + aLabeledSeqVector.push_back( xCategories ); + rOutSourceHasCategoryLabels = sal_Bool(xCategories.is()); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector( + lcl_getAllSeriesSequences( xChartDoc ) ); + + //the first x-values is always the next sequence //todo ... other x-values get lost for old format + Reference< chart2::data::XLabeledDataSequence > xXValues( + lcl_getDataSequenceByRole( aSeriesSeqVector, OUString::createFromAscii("values-x" ) ) ); + if( xXValues.is() ) + aLabeledSeqVector.push_back( xXValues ); + + //add all other sequences now without x-values + lcl_MatchesRole aHasXValues( OUString::createFromAscii("values-x" ) ); + for( sal_Int32 nN=0; nN<aSeriesSeqVector.getLength(); nN++ ) + { + if( !aHasXValues( aSeriesSeqVector[nN] ) ) + aLabeledSeqVector.push_back( aSeriesSeqVector[nN] ); + } + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( aLabeledSeqVector.size() ); + ::std::copy( aLabeledSeqVector.begin(), aLabeledSeqVector.end(), aSeq.getArray() ); + + return lcl_createDataSource( aSeq ); +} + +bool lcl_isSeriesAttachedToFirstAxis( + const Reference< chart2::XDataSeries > & xDataSeries ) +{ + bool bResult=true; + + try + { + sal_Int32 nAxisIndex = 0; + Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW ); + if( xProp.is() ) + xProp->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("AttachedAxisIndex") ) ) >>= nAxisIndex; + bResult = (0==nAxisIndex); + } + catch( uno::Exception & ex ) + { + (void)ex; // avoid warning for pro build + OSL_ENSURE( false, OUStringToOString( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught. Type: " )) + + OUString::createFromAscii( typeid( ex ).name()) + + OUString( RTL_CONSTASCII_USTRINGPARAM( ", Message: " )) + + ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); + } + + return bResult; +} + +OUString lcl_ConvertRange( const ::rtl::OUString & rRange, const Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if( !xDoc.is() ) + return aResult; + Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + if( xConversion.is()) + aResult = xConversion->convertRangeToXML( rRange ); + return aResult; +} + +typedef ::std::pair< OUString, OUString > tLabelAndValueRange; + +tLabelAndValueRange lcl_getLabelAndValueRangeByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt, + const OUString & rRole, + const Reference< chart2::XChartDocument > & xDoc, + SchXMLExportHelper_Impl::tDataSequenceCont & rOutSequencesToExport ) +{ + tLabelAndValueRange aResult; + + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + lcl_getDataSequenceByRole( aSeqCnt, rRole )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel()); + if( xLabelSeq.is()) + aResult.first = lcl_ConvertRange( xLabelSeq->getSourceRangeRepresentation(), xDoc ); + + Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues()); + if( xValueSeq.is()) + aResult.second = lcl_ConvertRange( xValueSeq->getSourceRangeRepresentation(), xDoc ); + + if( xLabelSeq.is() || xValueSeq.is()) + rOutSequencesToExport.push_back( SchXMLExportHelper_Impl::tLabelValuesDataPair( xLabelSeq, xValueSeq )); + } + + return aResult; +} + +sal_Int32 lcl_getSequenceLengthByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt, + const OUString & rRole ) +{ + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + lcl_getDataSequenceByRole( aSeqCnt, rRole )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getValues()); + return xSeq->getData().getLength(); + } + return 0; +} + +bool lcl_hasChartType( const Reference< chart2::XDiagram > & xDiagram, const OUString & rChartType ) +{ + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx ) + { + if( aChartTypes[nCTIdx]->getChartType().equals( rChartType )) + return true; + } + } + } + catch( uno::Exception & ) + { + DBG_ERROR( "Exception while searching for chart type in diagram" ); + } + return false; +} + +OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence ) +{ + OUStringBuffer aResult; + bool bPrecedeWithSpace = false; + for( sal_Int32 nIndex=0; nIndex<rSequence.getLength(); ++nIndex ) + { + if( rSequence[nIndex].getLength()) + { + if( bPrecedeWithSpace ) + aResult.append( static_cast< sal_Unicode >( ' ' )); + aResult.append( rSequence[nIndex] ); + bPrecedeWithSpace = true; + } + } + return aResult.makeStringAndClear(); +} + +OUString lcl_getLabelString( const Reference< chart2::data::XDataSequence > & xLabelSeq ) +{ + Sequence< OUString > aLabels; + + uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY ); + if( xTextualDataSequence.is()) + { + aLabels = xTextualDataSequence->getTextualData(); + } + else if( xLabelSeq.is()) + { + Sequence< uno::Any > aAnies( xLabelSeq->getData()); + aLabels.realloc( aAnies.getLength()); + for( sal_Int32 i=0; i<aAnies.getLength(); ++i ) + aAnies[i] >>= aLabels[i]; + } + + return lcl_flattenStringSequence( aLabels ); +} + +sal_Int32 lcl_getMaxSequenceLength( + const SchXMLExportHelper_Impl::tDataSequenceCont & rContainer ) +{ + sal_Int32 nResult = 0; + for( SchXMLExportHelper_Impl::tDataSequenceCont::const_iterator aIt( rContainer.begin()); + aIt != rContainer.end(); ++aIt ) + { + if( aIt->second.is()) + { + sal_Int32 nSeqLength = aIt->second->getData().getLength(); + if( nSeqLength > nResult ) + nResult = nSeqLength; + } + } + return nResult; +} + +double lcl_getValueFromSequence( const Reference< chart2::data::XDataSequence > & xSeq, sal_Int32 nIndex ) +{ + double fResult = 0.0; + ::rtl::math::setNan( &fResult ); + Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY ); + if( xNumSeq.is()) + { + Sequence< double > aValues( xNumSeq->getNumericalData()); + if( nIndex < aValues.getLength() ) + fResult = aValues[nIndex]; + } + else + { + Sequence< uno::Any > aAnies( xSeq->getData()); + if( nIndex < aAnies.getLength() ) + aAnies[nIndex] >>= fResult; + } + return fResult; +} + +::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq ) +{ + double fNan = 0.0; + ::rtl::math::setNan( &fNan ); + ::std::vector< double > aResult; + + Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY ); + if( xNumSeq.is()) + { + Sequence< double > aValues( xNumSeq->getNumericalData()); + ::std::copy( aValues.getConstArray(), aValues.getConstArray() + aValues.getLength(), + ::std::back_inserter( aResult )); + } + else if( xSeq.is()) + { + Sequence< uno::Any > aAnies( xSeq->getData()); + aResult.resize( aAnies.getLength(), fNan ); + for( sal_Int32 i=0; i<aAnies.getLength(); ++i ) + aAnies[i] >>= aResult[i]; + } + return aResult; +} + +bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + if( !xDataSequence.is() ) + return false; + uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is() ) + { + uno::Sequence< sal_Int32 > aHiddenValues; + try + { + xProp->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "HiddenValues" ) ) ) >>= aHiddenValues; + if( !aHiddenValues.getLength() ) + return true; + } + catch( uno::Exception& e ) + { + (void)e; // avoid warning + return true; + } + } + if( xDataSequence->getData().getLength() ) + return true; + return false; +} + +typedef vector< OUString > tStringVector; +typedef vector< vector< OUString > > t2DStringVector; +typedef vector< vector< double > > t2DNumberContainer; + +struct lcl_TableData +{ + t2DNumberContainer aDataInRows; + tStringVector aDataRangeRepresentations; + + tStringVector aColumnDescriptions; + tStringVector aColumnDescriptions_Ranges; + + tStringVector aRowDescriptions; + tStringVector aRowDescriptions_Ranges; + + Sequence< Sequence< OUString > > aComplexColumnDescriptions;//outer index is columns - inner index is level + Sequence< Sequence< OUString > > aComplexRowDescriptions;//outer index is rows - inner index is level + + ::std::vector< sal_Int32 > aHiddenColumns; +}; + +// ::std::bind2nd( ::std::mem_fun_ref( &T::resize ), nSize ) does not work +template< class T > + struct lcl_resize + { + lcl_resize( typename T::size_type nSize, typename T::value_type fDefaultValue ) : m_nSize( nSize ), m_fDefaultValue( fDefaultValue ) {} + void operator()( T & t ) + { t.resize( m_nSize, m_fDefaultValue ); } + private: + typename T::size_type m_nSize; + typename T::value_type m_fDefaultValue; + }; + + +typedef ::std::map< sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair > + lcl_DataSequenceMap; + +struct lcl_SequenceToMapElement : + public ::std::unary_function< lcl_DataSequenceMap::mapped_type, lcl_DataSequenceMap::value_type > +{ + lcl_SequenceToMapElement() + {} + result_type operator() ( const argument_type & rContent ) + { + sal_Int32 nIndex = -1; + if( rContent.second.is()) //has values + { + OUString aRangeRep( rContent.second->getSourceRangeRepresentation()); + nIndex = aRangeRep.toInt32(); + } + else if( rContent.first.is()) //has labels + nIndex = rContent.first->getSourceRangeRepresentation().copy( sizeof("label ")).toInt32(); + return result_type( nIndex, rContent ); + } +}; + +void lcl_ReorderInternalSequencesAccordingToTheirRangeName( + SchXMLExportHelper_Impl::tDataSequenceCont & rInOutSequences ) +{ + lcl_DataSequenceMap aIndexSequenceMap; + ::std::transform( rInOutSequences.begin(), rInOutSequences.end(), + ::std::inserter( aIndexSequenceMap, aIndexSequenceMap.begin()), + lcl_SequenceToMapElement()); + + rInOutSequences.clear(); + sal_Int32 nIndex = 0; + for( lcl_DataSequenceMap::const_iterator aIt = aIndexSequenceMap.begin(); + aIt != aIndexSequenceMap.end(); ++aIt, ++nIndex ) + { + if( aIt->first < 0 ) + continue; + // fill empty columns + for( ; nIndex < aIt->first; ++nIndex ) + rInOutSequences.push_back( + SchXMLExportHelper_Impl::tDataSequenceCont::value_type( 0, 0 )); + OSL_ASSERT( nIndex == aIt->first ); + rInOutSequences.push_back( aIt->second ); + } +} + + +lcl_TableData lcl_getDataForLocalTable( + const SchXMLExportHelper_Impl::tDataSequenceCont & aSequencesToExport, + const Reference< chart::XComplexDescriptionAccess >& xComplexDescriptionAccess, + const OUString& rCategoriesRange, + bool bSeriesFromColumns, + const Reference< chart2::data::XRangeXMLConversion > & xRangeConversion ) +{ + lcl_TableData aResult; + + try + { + Sequence< OUString > aSimpleCategories; + if( xComplexDescriptionAccess.is() ) + { + if( bSeriesFromColumns ) + aSimpleCategories = xComplexDescriptionAccess->getRowDescriptions(); + else + aSimpleCategories = xComplexDescriptionAccess->getColumnDescriptions(); + + aResult.aComplexColumnDescriptions = xComplexDescriptionAccess->getComplexColumnDescriptions(); + aResult.aComplexRowDescriptions = xComplexDescriptionAccess->getComplexRowDescriptions(); + } + + SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences = aSequencesToExport.size(); + SchXMLExportHelper_Impl::tDataSequenceCont::const_iterator aBegin( aSequencesToExport.begin()); + SchXMLExportHelper_Impl::tDataSequenceCont::const_iterator aEnd( aSequencesToExport.end()); + SchXMLExportHelper_Impl::tDataSequenceCont::const_iterator aIt( aBegin ); + + size_t nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport )); + size_t nCategoriesLength( aSimpleCategories.getLength() ); + if( nCategoriesLength > nMaxSequenceLength ) + { + aSimpleCategories.realloc(nMaxSequenceLength);//#i110617# + nCategoriesLength = nMaxSequenceLength; + } + size_t nNumColumns( bSeriesFromColumns ? nNumSequences : nMaxSequenceLength ); + size_t nNumRows( bSeriesFromColumns ? nMaxSequenceLength : nNumSequences ); + + // resize data + aResult.aDataInRows.resize( nNumRows ); + double fNan = 0.0; + ::rtl::math::setNan( &fNan ); + ::std::for_each( aResult.aDataInRows.begin(), aResult.aDataInRows.end(), + lcl_resize< t2DNumberContainer::value_type >( nNumColumns, fNan )); + aResult.aColumnDescriptions.resize( nNumColumns ); + aResult.aComplexColumnDescriptions.realloc( nNumColumns ); + aResult.aRowDescriptions.resize( nNumRows ); + aResult.aComplexRowDescriptions.realloc( nNumRows ); + + tStringVector& rCategories = bSeriesFromColumns ? aResult.aRowDescriptions : aResult.aColumnDescriptions; + tStringVector& rLabels = bSeriesFromColumns ? aResult.aColumnDescriptions : aResult.aRowDescriptions; + + //categories + lcl_SequenceToVector( aSimpleCategories, rCategories ); + if( rCategoriesRange.getLength() ) + { + OUString aRange(rCategoriesRange); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + if( bSeriesFromColumns ) + aResult.aRowDescriptions_Ranges.push_back( aRange ); + else + aResult.aColumnDescriptions_Ranges.push_back( aRange ); + } + + // iterate over all sequences + size_t nSeqIdx = 0; + for( ; aIt != aEnd; ++aIt, ++nSeqIdx ) + { + OUString aRange; + if( aIt->first.is()) + { + rLabels[nSeqIdx] = lcl_getLabelString( aIt->first ); + aRange = aIt->first->getSourceRangeRepresentation(); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + } + else if( aIt->second.is()) + rLabels[nSeqIdx] = lcl_flattenStringSequence( + aIt->second->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE )); + if( bSeriesFromColumns ) + aResult.aColumnDescriptions_Ranges.push_back( aRange ); + else + aResult.aRowDescriptions_Ranges.push_back( aRange ); + + ::std::vector< double > aNumbers( lcl_getAllValuesFromSequence( aIt->second )); + if( bSeriesFromColumns ) + { + const sal_Int32 nSize( static_cast< sal_Int32 >( aNumbers.size())); + for( sal_Int32 nIdx=0; nIdx<nSize; ++nIdx ) + aResult.aDataInRows[nIdx][nSeqIdx] = aNumbers[nIdx]; + } + else + aResult.aDataInRows[nSeqIdx] = aNumbers; + + if( aIt->second.is()) + { + aRange = aIt->second->getSourceRangeRepresentation(); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + } + aResult.aDataRangeRepresentations.push_back( aRange ); + + //is column hidden? + if( !lcl_SequenceHasUnhiddenData(aIt->first) && !lcl_SequenceHasUnhiddenData(aIt->second) ) + aResult.aHiddenColumns.push_back(nSeqIdx); + } + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + OSL_TRACE( OUStringToOString( OUString( RTL_CONSTASCII_USTRINGPARAM( + "something went wrong during table data collection: " )) + rEx.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); + } + + return aResult; +} + +void lcl_exportNumberFormat( const OUString& rPropertyName, const Reference< beans::XPropertySet >& xPropSet, + SvXMLExport& rExport ) +{ + if( xPropSet.is()) + { + sal_Int32 nNumberFormat = 0; + Any aNumAny = xPropSet->getPropertyValue( rPropertyName ); + if( (aNumAny >>= nNumberFormat) && (nNumberFormat != -1) ) + rExport.addDataStyle( nNumberFormat ); + } +} + +::std::vector< Reference< chart2::data::XDataSequence > > + lcl_getErrorBarSequences( const Reference< beans::XPropertySet > & xErrorBarProp ) +{ + ::std::vector< Reference< chart2::data::XDataSequence > > aResult; + Reference< chart2::data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY ); + if( !xErrorBarDataSource.is()) + return aResult; + + const OUString aRolePrefix( RTL_CONSTASCII_USTRINGPARAM( "error-bars-" )); +// const OUString aXRolePrefix( aRolePrefix + OUString( RTL_CONSTASCII_USTRINGPARAM( "x-" ))); +// const OUString aYRolePrefix( aRolePrefix + OUString( RTL_CONSTASCII_USTRINGPARAM( "y-" ))); +// const OUString aPositivePostfix( RTL_CONSTASCII_USTRINGPARAM( "positive" )); +// const OUString aNegativePostfix( RTL_CONSTASCII_USTRINGPARAM( "negative" )); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( + xErrorBarDataSource->getDataSequences()); + for( sal_Int32 nI=0; nI< aSequences.getLength(); ++nI ) + { + try + { + if( aSequences[nI].is()) + { + Reference< chart2::data::XDataSequence > xSequence( aSequences[nI]->getValues()); + Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW ); + OUString aRole; + if( ( xSeqProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Role" ))) >>= aRole ) && + aRole.match( aRolePrefix )) + { + aResult.push_back( xSequence ); + } + } + } + catch( uno::Exception & rEx ) + { +#ifdef DBG_UTIL + String aStr( rEx.Message ); + ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US ); + DBG_ERROR1( "chart:exporting error bar ranges: %s", aBStr.GetBuffer()); +#else + (void)rEx; // avoid warning +#endif + } + } + + return aResult; +} + +bool lcl_exportDomainForThisSequence( const Reference< chart2::data::XDataSequence > xValues, rtl::OUString& rFirstRangeForThisDomainIndex, SvXMLExport& rExport ) +{ + bool bDomainExported = false; + if( xValues.is()) + { + Reference< chart2::XChartDocument > xNewDoc( rExport.GetModel(), uno::UNO_QUERY ); + OUString aRange( lcl_ConvertRange( xValues->getSourceRangeRepresentation(), xNewDoc ) ); + + //work around error in OOo 2.0 (problems with multiple series having a domain element) + if( !rFirstRangeForThisDomainIndex.getLength() || !aRange.equals(rFirstRangeForThisDomainIndex) ) + { + rExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, aRange); + SvXMLElementExport aDomain( rExport, XML_NAMESPACE_CHART, XML_DOMAIN, sal_True, sal_True ); + bDomainExported = true; + } + + if( !rFirstRangeForThisDomainIndex.getLength() ) + rFirstRangeForThisDomainIndex = aRange; + } + return bDomainExported; +} + +} // anonymous namespace + +struct SchXMLDataPointStruct +{ + OUString maStyleName; + sal_Int32 mnRepeat; + + SchXMLDataPointStruct() : mnRepeat( 1 ) {} +}; + +// ======================================== +// class SchXMLExportHelper +// ======================================== + +SchXMLExportHelper::SchXMLExportHelper( SvXMLExport& rExport, SvXMLAutoStylePoolP& rASPool ) + : m_pImpl( new SchXMLExportHelper_Impl( rExport, rASPool ) ) +{ +} + +SchXMLExportHelper::~SchXMLExportHelper() +{ + delete m_pImpl; +} + +const OUString& SchXMLExportHelper::getChartCLSID() +{ + return m_pImpl->msCLSID; +} + +UniReference< XMLPropertySetMapper > SchXMLExportHelper_Impl::GetPropertySetMapper() const +{ + return mxPropertySetMapper; +} + +void SchXMLExportHelper_Impl::exportAutoStyles() +{ + if( mxExpPropMapper.is()) + { + //ToDo: when embedded in calc/writer this is not necessary because the + // numberformatter is shared between both documents + mrExport.exportAutoDataStyles(); + + // export chart auto styles + mrAutoStylePool.exportXML( + XML_STYLE_FAMILY_SCH_CHART_ID + , mrExport.GetDocHandler(), + mrExport.GetMM100UnitConverter(), + mrExport.GetNamespaceMap() + ); + + // export auto styles for additional shapes + mrExport.GetShapeExport()->exportAutoStyles(); + // and for text in additional shapes + mrExport.GetTextParagraphExport()->exportTextAutoStyles(); + } +} + +// private methods +// --------------- + +SchXMLExportHelper_Impl::SchXMLExportHelper_Impl( + SvXMLExport& rExport, + SvXMLAutoStylePoolP& rASPool ) : + mrExport( rExport ), + mrAutoStylePool( rASPool ), + mbHasSeriesLabels( sal_False ), + mbHasCategoryLabels( sal_False ), + mbRowSourceColumns( sal_True ) + // #110680# + // this id depends on the ServiceManager used due to the binary filter stripping. + // ,msCLSID( rtl::OUString( SvGlobalName( SO3_SCH_CLASSID ).GetHexName())) +{ + // #110680# + // changed initialisation for msCLSID. Compare the ServiceInfo name with + // the known name of the LegacyServiceManager. + Reference<lang::XServiceInfo> xServiceInfo( mrExport.getServiceFactory(), uno::UNO_QUERY ); + DBG_ASSERT( xServiceInfo.is(), "XMultiServiceFactory without xServiceInfo (!)" ); + OUString rdbURL = xServiceInfo->getImplementationName(); + OUString implLegacyServiceManagerName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.office.LegacyServiceManager" ) ); + + if( rdbURL.equals( implLegacyServiceManagerName )) + { + msCLSID = OUString( SvGlobalName( BF_SO3_SCH_CLASSID ).GetHexName()); + } + else + { + msCLSID = OUString( SvGlobalName( SO3_SCH_CLASSID ).GetHexName()); + } + + msTableName = OUString::createFromAscii( "local-table" ); + + // create factory + mxPropertyHandlerFactory = new XMLChartPropHdlFactory; + + if( mxPropertyHandlerFactory.is() ) + { + // create property set mapper + mxPropertySetMapper = new XMLChartPropertySetMapper; + } + + mxExpPropMapper = new XMLChartExportPropertyMapper( mxPropertySetMapper, rExport ); + + // register chart auto-style family + mrAutoStylePool.AddFamily( + XML_STYLE_FAMILY_SCH_CHART_ID, + OUString::createFromAscii( XML_STYLE_FAMILY_SCH_CHART_NAME ), + mxExpPropMapper.get(), + OUString::createFromAscii( XML_STYLE_FAMILY_SCH_CHART_PREFIX )); + + // register shape family + mrAutoStylePool.AddFamily( + XML_STYLE_FAMILY_SD_GRAPHICS_ID, + OUString::createFromAscii( XML_STYLE_FAMILY_SD_GRAPHICS_NAME ), + mxExpPropMapper.get(), + OUString::createFromAscii( XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX )); + // register paragraph family also for shapes + mrAutoStylePool.AddFamily( + XML_STYLE_FAMILY_TEXT_PARAGRAPH, + GetXMLToken( XML_PARAGRAPH ), + mxExpPropMapper.get(), + String( 'P' )); + // register text family also for shapes + mrAutoStylePool.AddFamily( + XML_STYLE_FAMILY_TEXT_TEXT, + GetXMLToken( XML_TEXT ), + mxExpPropMapper.get(), + String( 'T' )); +} + +SchXMLExportHelper_Impl::~SchXMLExportHelper_Impl() +{ +} + +void SchXMLExportHelper_Impl::collectAutoStyles( Reference< chart::XChartDocument > rChartDoc ) +{ + parseDocument( rChartDoc, sal_False ); +} + +void SchXMLExportHelper_Impl::exportChart( Reference< chart::XChartDocument > rChartDoc, + sal_Bool bIncludeTable ) +{ + parseDocument( rChartDoc, sal_True, bIncludeTable ); + DBG_ASSERT( maAutoStyleNameQueue.empty(), "There are still remaining autostyle names in the queue" ); +} + +::rtl::OUString lcl_GetStringFromNumberSequence( const ::com::sun::star::uno::Sequence< sal_Int32 >& rSequenceMapping, bool bRemoveOneFromEachIndex /*should be true if having categories*/ ) +{ + const sal_Int32* pArray = rSequenceMapping.getConstArray(); + const sal_Int32 nSize = rSequenceMapping.getLength(); + sal_Int32 i = 0; + OUStringBuffer aBuf; + bool bHasPredecessor = false; + for( i = 0; i < nSize; ++i ) + { + sal_Int32 nIndex = pArray[ i ]; + if( bRemoveOneFromEachIndex ) + --nIndex; + if(nIndex>=0) + { + if(bHasPredecessor) + aBuf.append( static_cast< sal_Unicode >( ' ' )); + aBuf.append( nIndex, 10 ); + bHasPredecessor = true; + } + } + return aBuf.makeStringAndClear(); +} + +/// if bExportContent is false the auto-styles are collected +void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument >& rChartDoc, + sal_Bool bExportContent, + sal_Bool bIncludeTable ) +{ + Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY ); + if( !rChartDoc.is() || !xNewDoc.is() ) + { + DBG_ERROR( "No XChartDocument was given for export." ); + return; + } + + awt::Size aPageSize( getPageSize( xNewDoc )); + if( bExportContent ) + addSize( aPageSize ); + Reference< chart::XDiagram > xDiagram = rChartDoc->getDiagram(); + Reference< chart2::XDiagram > xNewDiagram; + if( xNewDoc.is()) + xNewDiagram.set( xNewDoc->getFirstDiagram()); + + //todo remove if model changes are notified and view is updated automatically + if( bExportContent ) + { + Reference< util::XRefreshable > xRefreshable( xNewDoc, uno::UNO_QUERY ); + if( xRefreshable.is() ) + xRefreshable->refresh(); + } + + // get Properties of ChartDocument + sal_Bool bHasMainTitle = sal_False; + sal_Bool bHasSubTitle = sal_False; + sal_Bool bHasLegend = sal_False; + util::DateTime aNullDate(0,0,0,0,30,12,1899); + + std::vector< XMLPropertyState > aPropertyStates; + + Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY ); + if( xDocPropSet.is()) + { + try + { + Any aAny( xDocPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "HasMainTitle" )))); + aAny >>= bHasMainTitle; + aAny = xDocPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "HasSubTitle" ))); + aAny >>= bHasSubTitle; + aAny = xDocPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "HasLegend" ))); + aAny >>= bHasLegend; + if ( bIncludeTable ) + { + OUString sNullDate( RTL_CONSTASCII_USTRINGPARAM( "NullDate" )); + aAny = xDocPropSet->getPropertyValue(sNullDate); + if ( !aAny.hasValue() ) + { + Reference<container::XChild> xChild(rChartDoc, uno::UNO_QUERY ); + if ( xChild.is() ) + { + Reference< beans::XPropertySet > xParentDoc( xChild->getParent(),uno::UNO_QUERY); + if ( xParentDoc.is() && xParentDoc->getPropertySetInfo()->hasPropertyByName(sNullDate) ) + aAny = xParentDoc->getPropertyValue(sNullDate); + } + } + + aAny >>= aNullDate; + } + } + catch( beans::UnknownPropertyException & ) + { + DBG_WARNING( "Required property not found in ChartDocument" ); + } + } // if( xDocPropSet.is()) + + if ( bIncludeTable && (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 ) ) + { + SvXMLElementExport aSet( mrExport, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, sal_True, sal_True ); + { + ::rtl::OUStringBuffer sBuffer; + SvXMLUnitConverter::convertDateTime(sBuffer,aNullDate); + mrExport.AddAttribute( XML_NAMESPACE_TABLE,XML_DATE_VALUE,sBuffer.makeStringAndClear()); + SvXMLElementExport aNull( mrExport, XML_NAMESPACE_TABLE, XML_NULL_DATE, sal_True, sal_True ); + } + } + + // chart element + // ------------- + + SvXMLElementExport* pElChart = 0; + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getArea(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + //export data provider in xlink:href attribute + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 ) + { + OUString aDataProviderURL( RTL_CONSTASCII_USTRINGPARAM( ".." ) ); + if( xNewDoc->hasInternalDataProvider() ) + aDataProviderURL = OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ); + else //special handling for data base data provider necessary + { + Reference< chart2::data::XDatabaseDataProvider > xDBDataProvider( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + if( xDBDataProvider.is() ) + aDataProviderURL = OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ); + } + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aDataProviderURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + } + + OUString sChartType( xDiagram->getDiagramType() ); + + // attributes + // determine class + if( sChartType.getLength()) + { + enum XMLTokenEnum eXMLChartType = SchXMLTools::getTokenByChartType( sChartType, true /* bUseOldNames */ ); + + DBG_ASSERT( eXMLChartType != XML_TOKEN_INVALID, "invalid chart class" ); + if( eXMLChartType == XML_TOKEN_INVALID ) + eXMLChartType = XML_BAR; + + if( eXMLChartType == XML_ADD_IN ) + { + // sChartType is the servie-name of the add-in + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, sChartType) ); + } + else if( eXMLChartType != XML_TOKEN_INVALID ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) ); + } + + //column-mapping or row-mapping + if( maSequenceMapping.getLength() ) + { + enum XMLTokenEnum eTransToken = ::xmloff::token::XML_ROW_MAPPING; + if( mbRowSourceColumns ) + eTransToken = ::xmloff::token::XML_COLUMN_MAPPING; + ::rtl::OUString aSequenceMappingStr( lcl_GetStringFromNumberSequence( + maSequenceMapping, mbHasCategoryLabels && !xNewDoc->hasInternalDataProvider() ) ); + + mrExport.AddAttribute( XML_NAMESPACE_CHART, + ::xmloff::token::GetXMLToken( eTransToken ), + aSequenceMappingStr ); + } + } + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + //element + pElChart = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_CHART, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + + // title element + // ------------- + + if( bHasMainTitle ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getTitle(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + Reference< drawing::XShape > xShape = rChartDoc->getTitle(); + if( xShape.is()) // && "hasTitleBeenMoved" + addPosition( xShape ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, sal_True, sal_True ); + + // content (text:p) + Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is()) + { + Any aAny( xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + OUString aText; + aAny >>= aText; + exportText( aText ); + } + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // subtitle element + // ---------------- + + if( bHasSubTitle ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getSubTitle(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + Reference< drawing::XShape > xShape = rChartDoc->getSubTitle(); + if( xShape.is()) + addPosition( xShape ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element (has no subelements) + SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, sal_True, sal_True ); + + // content (text:p) + Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is()) + { + Any aAny( xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + OUString aText; + aAny >>= aText; + exportText( aText ); + } + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // legend element + // -------------- + if( bHasLegend ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getLegend(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY ); + if( xProp.is()) + { + chart::ChartLegendPosition aLegendPos = chart::ChartLegendPosition_NONE; + try + { + Any aAny( xProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Alignment" )))); + aAny >>= aLegendPos; + } + catch( beans::UnknownPropertyException & ) + { + DBG_WARNING( "Property Align not found in ChartLegend" ); + } + + switch( aLegendPos ) + { + case chart::ChartLegendPosition_LEFT: +// msString = GetXMLToken(XML_LEFT); + // #i35421# change left->start (not clear why this was done) + msString = GetXMLToken(XML_START); + break; + case chart::ChartLegendPosition_RIGHT: +// msString = GetXMLToken(XML_RIGHT); + // #i35421# change right->end (not clear why this was done) + msString = GetXMLToken(XML_END); + break; + case chart::ChartLegendPosition_TOP: + msString = GetXMLToken(XML_TOP); + break; + case chart::ChartLegendPosition_BOTTOM: + msString = GetXMLToken(XML_BOTTOM); + break; + case chart::ChartLegendPosition_NONE: + case chart::ChartLegendPosition_MAKE_FIXED_SIZE: + // nothing + break; + } + + // export anchor position + if( msString.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LEGEND_POSITION, msString ); + + // export absolute position + msString = OUString(); + Reference< drawing::XShape > xShape( xProp, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + } + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + SvXMLElementExport aLegend( mrExport, XML_NAMESPACE_CHART, XML_LEGEND, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // plot-area element + // ----------------- + if( xDiagram.is()) + exportPlotArea( xDiagram, xNewDiagram, aPageSize, bExportContent, bIncludeTable ); + + // export additional shapes + // ------------------------ + if( xDocPropSet.is() ) + { + if( bExportContent ) + { + if( mxAdditionalShapes.is()) + { + // can't call exportShapes with all shapes because the + // initialisation happend with the complete draw page and not + // the XShapes object used here. Thus the shapes have to be + // exported one by one + UniReference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport(); + Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount( mxAdditionalShapes->getCount()); + for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ ) + { + mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape; + DBG_ASSERT( xShape.is(), "Shape without an XShape?" ); + if( ! xShape.is()) + continue; + + rShapeExport->exportShape( xShape ); + } + // this would be the easier way if it worked: + //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes ); + } + } + else + { + // get a sequence of non-chart shapes (inserted via clipboard) + try + { + Any aShapesAny = xDocPropSet->getPropertyValue( OUString::createFromAscii( "AdditionalShapes" )); + aShapesAny >>= mxAdditionalShapes; + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + OSL_TRACE( + OUStringToOString( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "AdditionalShapes not found: " )) + + rEx.Message, + RTL_TEXTENCODING_ASCII_US ).getStr()); + } + + if( mxAdditionalShapes.is()) + { + // seek shapes has to be called for the whole page because in + // the shape export the vector of shapes is accessed via the + // ZOrder which might be (actually is) larger than the number of + // shapes in mxAdditionalShapes + Reference< drawing::XDrawPageSupplier > xSupplier( rChartDoc, uno::UNO_QUERY ); + DBG_ASSERT( xSupplier.is(), "Cannot retrieve draw page to initialize shape export" ); + if( xSupplier.is() ) + { + Reference< drawing::XShapes > xDrawPage( xSupplier->getDrawPage(), uno::UNO_QUERY ); + DBG_ASSERT( xDrawPage.is(), "Invalid draw page for initializing shape export" ); + if( xDrawPage.is()) + mrExport.GetShapeExport()->seekShapes( xDrawPage ); + } + + // can't call collectShapesAutoStyles with all shapes because + // the initialisation happend with the complete draw page and + // not the XShapes object used here. Thus the shapes have to be + // exported one by one + UniReference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport(); + Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount( mxAdditionalShapes->getCount()); + for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ ) + { + mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape; + DBG_ASSERT( xShape.is(), "Shape without an XShape?" ); + if( ! xShape.is()) + continue; + + rShapeExport->collectShapeAutoStyles( xShape ); + } + // this would be the easier way if it worked: + // mrExport.GetShapeExport()->collectShapesAutoStyles( mxAdditionalShapes ); + } + } + } + + // table element + // (is included as subelement of chart) + // ------------------------------------ + if( bExportContent ) + { + // #85929# always export table, otherwise clipboard may loose data + exportTable(); + } + + // close <chart:chart> element + if( pElChart ) + delete pElChart; +} + +void lcl_exportComplexLabel( const Sequence< OUString >& rComplexLabel, SvXMLExport& rExport ) +{ + sal_Int32 nLength = rComplexLabel.getLength(); + if( nLength<=1 ) + return; + SvXMLElementExport aTextList( rExport, XML_NAMESPACE_TEXT, XML_LIST, sal_True, sal_True ); + for(sal_Int32 nN=0; nN<nLength; nN++) + { + SvXMLElementExport aListItem( rExport, XML_NAMESPACE_TEXT, XML_LIST_ITEM, sal_True, sal_True ); + SchXMLTools::exportText( rExport, rComplexLabel[nN], false /*bConvertTabsLFs*/ ); + } +} + +void SchXMLExportHelper_Impl::exportTable() +{ + // table element + // ------------- + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, msTableName ); + SvXMLElementExport aTable( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, sal_True, sal_True ); + + bool bHasOwnData = false; + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + Reference< chart2::data::XRangeXMLConversion > xRangeConversion; + if( xNewDoc.is()) + { + bHasOwnData = xNewDoc->hasInternalDataProvider(); + xRangeConversion.set( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + } + + Reference< chart::XComplexDescriptionAccess > xComplexDescriptionAccess; + { + Reference< chart::XChartDocument > xChartDoc( mrExport.GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() ) + xComplexDescriptionAccess = Reference< chart::XComplexDescriptionAccess >( xChartDoc->getData(), uno::UNO_QUERY ); + } + + if( bHasOwnData ) + lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport ); + lcl_TableData aData( lcl_getDataForLocalTable( m_aDataSequencesToExport + , xComplexDescriptionAccess, maCategoriesRange + , mbRowSourceColumns, xRangeConversion )); + + tStringVector::const_iterator aDataRangeIter( aData.aDataRangeRepresentations.begin()); + const tStringVector::const_iterator aDataRangeEndIter( aData.aDataRangeRepresentations.end()); + + tStringVector::const_iterator aRowDescriptions_RangeIter( aData.aRowDescriptions_Ranges.begin()); + const tStringVector::const_iterator aRowDescriptions_RangeEnd( aData.aRowDescriptions_Ranges.end()); + + // declare columns + { + SvXMLElementExport aHeaderColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, sal_True, sal_True ); + SvXMLElementExport aHeaderColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, sal_True, sal_True ); + } + { + SvXMLElementExport aColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, sal_True, sal_True ); + + sal_Int32 nNextIndex = 0; + for( size_t nN=0; nN< aData.aHiddenColumns.size(); nN++ ) + { + //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste ) + sal_Int32 nHiddenIndex = aData.aHiddenColumns[nN]; + if( nHiddenIndex > nNextIndex ) + { + sal_Int64 nRepeat = static_cast< sal_Int64 >( nHiddenIndex - nNextIndex ); + if(nRepeat>1) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::valueOf( nRepeat )); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, sal_True, sal_True ); + } + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_VISIBILITY, GetXMLToken( XML_COLLAPSE ) ); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, sal_True, sal_True ); + nNextIndex = nHiddenIndex+1; + } + + sal_Int32 nEndIndex = aData.aColumnDescriptions.size()-1; + if( nEndIndex >= nNextIndex ) + { + sal_Int64 nRepeat = static_cast< sal_Int64 >( nEndIndex - nNextIndex + 1 ); + if(nRepeat>1) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::valueOf( nRepeat )); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, sal_True, sal_True ); + } + } + + // export rows with content + //export header row + { + SvXMLElementExport aHeaderRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, sal_True, sal_True ); + SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True ); + + //first one empty cell for the row descriptions + { + SvXMLElementExport aEmptyCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True ); + SvXMLElementExport aEmptyParagraph( mrExport, XML_NAMESPACE_TEXT, XML_P, sal_True, sal_True ); + } + + //export column descriptions + tStringVector::const_iterator aColumnDescriptions_RangeIter( aData.aColumnDescriptions_Ranges.begin()); + const tStringVector::const_iterator aColumnDescriptions_RangeEnd( aData.aColumnDescriptions_Ranges.end()); + const Sequence< Sequence< OUString > >& rComplexColumnDescriptions = aData.aComplexColumnDescriptions; + sal_Int32 nComplexCount = rComplexColumnDescriptions.getLength(); + sal_Int32 nC = 0; + for( tStringVector::const_iterator aIt( aData.aColumnDescriptions.begin()); + aIt != aData.aColumnDescriptions.end(); ++aIt ) + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING ); + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True ); + exportText( *aIt ); + if( nC < nComplexCount ) + lcl_exportComplexLabel( rComplexColumnDescriptions[nC++], mrExport ); + if( !bHasOwnData && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd ) + { + // remind the original range to allow a correct re-association when copying via clipboard + if ((*aColumnDescriptions_RangeIter).getLength()) + SchXMLTools::exportRangeToSomewhere( mrExport, *aColumnDescriptions_RangeIter ); + ++aColumnDescriptions_RangeIter; + } + } + OSL_ASSERT( bHasOwnData || aColumnDescriptions_RangeIter == aColumnDescriptions_RangeEnd ); + } // closing row and header-rows elements + + // export value rows + { + SvXMLElementExport aRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROWS, sal_True, sal_True ); + tStringVector::const_iterator aRowDescriptionsIter( aData.aRowDescriptions.begin()); + const Sequence< Sequence< OUString > >& rComplexRowDescriptions = aData.aComplexRowDescriptions; + sal_Int32 nComplexCount = rComplexRowDescriptions.getLength(); + sal_Int32 nC = 0; + + for( t2DNumberContainer::const_iterator aRowIt( aData.aDataInRows.begin()); + aRowIt != aData.aDataInRows.end(); ++aRowIt ) + { + SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True ); + + //export row descriptions + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING ); + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True ); + if( aRowDescriptionsIter != aData.aRowDescriptions.end()) + { + exportText( *aRowDescriptionsIter ); + ++aRowDescriptionsIter; + if( nC < nComplexCount ) + lcl_exportComplexLabel( rComplexRowDescriptions[nC++], mrExport ); + if( !bHasOwnData && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd ) + { + // remind the original range to allow a correct re-association when copying via clipboard + SchXMLTools::exportRangeToSomewhere( mrExport, *aRowDescriptions_RangeIter++ ); + } + } + } + + //export row values + for( t2DNumberContainer::value_type::const_iterator aColIt( aRowIt->begin()); + aColIt != aRowIt->end(); ++aColIt ) + { + SvXMLUnitConverter::convertDouble( msStringBuffer, *aColIt ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True ); + exportText( msString, false ); // do not convert tabs and lfs + if( ( !bHasOwnData && aDataRangeIter != aDataRangeEndIter ) && + ( mbRowSourceColumns || (aColIt == aRowIt->begin()) ) ) + { + // remind the original range to allow a correct re-association when copying via clipboard + if ((*aDataRangeIter).getLength()) + SchXMLTools::exportRangeToSomewhere( mrExport, *aDataRangeIter ); + ++aDataRangeIter; + } + } + } + } + + // if range iterator was used it should have reached its end + OSL_ASSERT( bHasOwnData || (aDataRangeIter == aDataRangeEndIter) ); + OSL_ASSERT( bHasOwnData || (aRowDescriptions_RangeIter == aRowDescriptions_RangeEnd) ); +} + +void SchXMLExportHelper_Impl::exportPlotArea( + Reference< chart::XDiagram > xDiagram, + Reference< chart2::XDiagram > xNewDiagram, + const awt::Size & rPageSize, + sal_Bool bExportContent, + sal_Bool bIncludeTable ) +{ + DBG_ASSERT( xDiagram.is(), "Invalid XDiagram as parameter" ); + if( ! xDiagram.is()) + return; + + // variables for autostyles + Reference< beans::XPropertySet > xPropSet; + std::vector< XMLPropertyState > aPropertyStates; + + OUString aASName; + sal_Bool bHasTwoYAxes = sal_False; + sal_Bool bIs3DChart = sal_False; + drawing::HomogenMatrix aTransMatrix; + + msStringBuffer.setLength( 0 ); + + // plot-area element + // ----------------- + + SvXMLElementExport* pElPlotArea = 0; + // get property states for autostyles + xPropSet = Reference< beans::XPropertySet >( xDiagram, uno::UNO_QUERY ); + if( xPropSet.is()) + { + if( mxExpPropMapper.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + UniReference< XMLShapeExport > rShapeExport; + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + if( msChartAddress.getLength() ) + { + if( !bIncludeTable ) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, msChartAddress ); + + Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY ); + if( xDoc.is() ) + { + Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY ); + if( xDocProp.is()) + { + Any aAny; + sal_Bool bFirstCol = false, bFirstRow = false; + + try + { + aAny = xDocProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "DataSourceLabelsInFirstColumn" ))); + aAny >>= bFirstCol; + aAny = xDocProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "DataSourceLabelsInFirstRow" ))); + aAny >>= bFirstRow; + + if( bFirstCol || bFirstRow ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS ), + ( bFirstCol + ? ( bFirstRow + ? ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH ) + : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN )) + : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW ))); + } + } + catch( beans::UnknownPropertyException & ) + { + DBG_ERRORFILE( "Properties missing" ); + } + } + } + } + + // #i72973#, #144135# only export table-number-list in OOo format (also for binary) + Reference< beans::XPropertySet > xExportInfo( mrExport.getExportInfo()); + if( msTableNumberList.getLength() && + xExportInfo.is()) + { + try + { + OUString sExportTableNumListPropName( RTL_CONSTASCII_USTRINGPARAM("ExportTableNumberList")); + Reference< beans::XPropertySetInfo > xInfo( xExportInfo->getPropertySetInfo()); + bool bExportTableNumberList = false; + if( xInfo.is() && xInfo->hasPropertyByName( sExportTableNumListPropName ) && + (xExportInfo->getPropertyValue( sExportTableNumListPropName ) >>= bExportTableNumberList) && + bExportTableNumberList ) + { + // this attribute is for charts embedded in calc documents only. + // With this you are able to store a file again in 5.0 binary format + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_TABLE_NUMBER_LIST, msTableNumberList ); + } + } + catch( uno::Exception & rEx ) + { +#ifdef DBG_UTIL + String aStr( rEx.Message ); + ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US ); + DBG_ERROR1( "chart:TableNumberList property caught: %s", aBStr.GetBuffer()); +#else + (void)rEx; // avoid warning +#endif + } + } + + // attributes + Reference< drawing::XShape > xShape ( xDiagram, uno::UNO_QUERY ); + if( xShape.is()) + { + addPosition( xShape ); + addSize( xShape ); + } + + if( xPropSet.is()) + { + Any aAny; + try + { + aAny = xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "HasSecondaryYAxis" ))); + aAny >>= bHasTwoYAxes; + } + catch( beans::UnknownPropertyException & ) + { + DBG_ERROR( "Property HasSecondaryYAxis not found in Diagram" ); + } + + // 3d attributes + try + { + aAny = xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Dim3D" ))); + aAny >>= bIs3DChart; + + if( bIs3DChart ) + { + rShapeExport = mrExport.GetShapeExport(); + if( rShapeExport.is()) + rShapeExport->export3DSceneAttributes( xPropSet ); + } + } + catch( uno::Exception & rEx ) + { +#ifdef DBG_UTIL + String aStr( rEx.Message ); + ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US ); + DBG_ERROR1( "chart:exportPlotAreaException caught: %s", aBStr.GetBuffer()); +#else + (void)rEx; // avoid warning +#endif + } + } + + // plot-area element + pElPlotArea = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_PLOT_AREA, sal_True, sal_True ); + + //inner position rectangle element + exportCoordinateRegion( xDiagram ); + + // light sources (inside plot area element) + if( bIs3DChart && + rShapeExport.is()) + rShapeExport->export3DLamps( xPropSet ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + + // axis elements + // ------------- + exportAxes( xDiagram, xNewDiagram, bExportContent ); + + // series elements + // --------------- + exportSeries( xNewDiagram, rPageSize, bExportContent, bHasTwoYAxes ); + + // stock-chart elements + OUString sChartType ( xDiagram->getDiagramType()); + if( 0 == sChartType.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart.StockDiagram" ))) + { + Reference< chart::XStatisticDisplay > xStockPropProvider( xDiagram, uno::UNO_QUERY ); + if( xStockPropProvider.is()) + { + // stock-gain-marker + Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getUpBar(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter( xStockPropSet ); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_GAIN_MARKER, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + + // stock-loss-marker + xStockPropSet = xStockPropProvider->getDownBar(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter( xStockPropSet ); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_LOSS_MARKER, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + + // stock-range-line + xStockPropSet = xStockPropProvider->getMinMaxLine(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter( xStockPropSet ); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_RANGE_LINE, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + } + + // wall and floor element + // ---------------------- + + Reference< chart::X3DDisplay > xWallFloorSupplier( xDiagram, uno::UNO_QUERY ); + if( mxExpPropMapper.is() && + xWallFloorSupplier.is()) + { + // remove property states for autostyles + aPropertyStates.clear(); + + Reference< beans::XPropertySet > xWallPropSet( xWallFloorSupplier->getWall(), uno::UNO_QUERY ); + if( xWallPropSet.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xWallPropSet ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aWall( mrExport, XML_NAMESPACE_CHART, XML_WALL, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + + // floor element + // ------------- + + // remove property states for autostyles + aPropertyStates.clear(); + + Reference< beans::XPropertySet > xFloorPropSet( xWallFloorSupplier->getFloor(), uno::UNO_QUERY ); + if( xFloorPropSet.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xFloorPropSet ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aFloor( mrExport, XML_NAMESPACE_CHART, XML_FLOOR, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + + if( pElPlotArea ) + delete pElPlotArea; +} + +void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference< chart::XDiagram >& xDiagram ) +{ + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentODFVersion <= SvtSaveOptions::ODFVER_012 )//do not export to ODF 1.2 or older + return; + if( nCurrentODFVersion != SvtSaveOptions::ODFVER_LATEST )//export only if extensions are enabled //#i100778# todo: change this dependent on fileformat evolution + return; + + Reference< chart::XDiagramPositioning > xDiaPos( xDiagram, uno::UNO_QUERY ); + DBG_ASSERT( xDiaPos.is(), "Invalid xDiaPos as parameter" ); + if( !xDiaPos.is() ) + return; + + awt::Rectangle aRect( xDiaPos->calculateDiagramPositionExcludingAxes() ); + addPosition( awt::Point(aRect.X,aRect.Y) ); + addSize( awt::Size(aRect.Width,aRect.Height) ); + + SvXMLElementExport aCoordinateRegion( mrExport, XML_NAMESPACE_CHART_EXT, XML_COORDINATE_REGION, sal_True, sal_True );//#i100778# todo: change to chart namespace in future - dependent on fileformat +} + +void SchXMLExportHelper_Impl::exportAxes( + const Reference< chart::XDiagram > & xDiagram, + const Reference< chart2::XDiagram > & xNewDiagram, + sal_Bool bExportContent ) +{ + DBG_ASSERT( xDiagram.is(), "Invalid XDiagram as parameter" ); + if( ! xDiagram.is()) + return; + + // variables for autostyles + const OUString sNumFormat( OUString::createFromAscii( "NumberFormat" )); + Reference< beans::XPropertySet > xPropSet; + std::vector< XMLPropertyState > aPropertyStates; + + OUString aASName; + + // get some properties from document first + sal_Bool bHasXAxis = sal_False, + bHasYAxis = sal_False, + bHasZAxis = sal_False, + bHasSecondaryXAxis = sal_False, + bHasSecondaryYAxis = sal_False; + sal_Bool bHasXAxisTitle = sal_False, + bHasYAxisTitle = sal_False, + bHasZAxisTitle = sal_False, + bHasSecondaryXAxisTitle = sal_False, + bHasSecondaryYAxisTitle = sal_False; + sal_Bool bHasXAxisMajorGrid = sal_False, + bHasXAxisMinorGrid = sal_False, + bHasYAxisMajorGrid = sal_False, + bHasYAxisMinorGrid = sal_False, + bHasZAxisMajorGrid = sal_False, + bHasZAxisMinorGrid = sal_False; + sal_Bool bIs3DChart = sal_False; + + // get multiple properties using XMultiPropertySet + MultiPropertySetHandler aDiagramProperties (xDiagram); + + // Check for supported services and then the properties provided by this service. + Reference<lang::XServiceInfo> xServiceInfo (xDiagram, uno::UNO_QUERY); + if (xServiceInfo.is()) + { + if (xServiceInfo->supportsService( + OUString::createFromAscii ("com.sun.star.chart.ChartAxisXSupplier"))) + { + aDiagramProperties.Add ( + OUString(RTL_CONSTASCII_USTRINGPARAM("HasXAxis")), bHasXAxis); + } + if (xServiceInfo->supportsService( + OUString::createFromAscii ("com.sun.star.chart.ChartAxisYSupplier"))) + { + aDiagramProperties.Add ( + OUString(RTL_CONSTASCII_USTRINGPARAM("HasYAxis")), bHasYAxis); + } + if (xServiceInfo->supportsService( + OUString::createFromAscii ("com.sun.star.chart.ChartAxisZSupplier"))) + { + aDiagramProperties.Add ( + OUString(RTL_CONSTASCII_USTRINGPARAM("HasZAxis")), bHasZAxis); + } + if (xServiceInfo->supportsService( + OUString::createFromAscii ("com.sun.star.chart.ChartTwoAxisXSupplier"))) + { + aDiagramProperties.Add ( + OUString(RTL_CONSTASCII_USTRINGPARAM("HasSecondaryXAxis")), bHasSecondaryXAxis); + } + if (xServiceInfo->supportsService( + OUString::createFromAscii ("com.sun.star.chart.ChartTwoAxisYSupplier"))) + { + aDiagramProperties.Add ( + OUString(RTL_CONSTASCII_USTRINGPARAM("HasSecondaryYAxis")), bHasSecondaryYAxis); + } + } + + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasXAxisTitle")), bHasXAxisTitle); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasYAxisTitle")), bHasYAxisTitle); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasZAxisTitle")), bHasZAxisTitle); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasSecondaryXAxisTitle")), bHasSecondaryXAxisTitle); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasSecondaryYAxisTitle")), bHasSecondaryYAxisTitle); + + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasXAxisGrid")), bHasXAxisMajorGrid); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasYAxisGrid")), bHasYAxisMajorGrid); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasZAxisGrid")), bHasZAxisMajorGrid); + + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasXAxisHelpGrid")), bHasXAxisMinorGrid); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasYAxisHelpGrid")), bHasYAxisMinorGrid); + aDiagramProperties.Add ( + OUString (RTL_CONSTASCII_USTRINGPARAM ("HasZAxisHelpGrid")), bHasZAxisMinorGrid); + + aDiagramProperties.Add( + OUString (RTL_CONSTASCII_USTRINGPARAM ("Dim3D")), bIs3DChart); + + if ( ! aDiagramProperties.GetProperties ()) + { + DBG_WARNING ("Required properties not found in Chart diagram"); + } + + SvXMLElementExport* pAxis = NULL; + + // x axis + // ------- + + // write axis element also if the axis itself is not visible, but a grid or + // title + Reference< chart::XAxisXSupplier > xAxisXSupp( xDiagram, uno::UNO_QUERY ); + if( xAxisXSupp.is()) + { + bool bHasAxisProperties = false; + // get property states for autostyles + if( mxExpPropMapper.is()) + { + xPropSet = xAxisXSupp->getXAxis(); + if( xPropSet.is()) + { + bHasAxisProperties = true; + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + } + + if( bHasXAxis || + bHasXAxisTitle || bHasXAxisMajorGrid || bHasXAxisMinorGrid || + mbHasCategoryLabels || bHasAxisProperties ) + { + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, XML_X ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, XML_PRIMARY_X ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + pAxis = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + + // axis-title + if( bHasXAxisTitle ) + { + Reference< beans::XPropertySet > xTitleProp( xAxisXSupp->getXAxisTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xTitleProp ); + if( bExportContent ) + { + OUString aText; + Any aAny( xTitleProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + aAny >>= aText; + + Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, sal_True, sal_True ); + + // paragraph containing title + exportText( aText ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + } + + // categories if we have a categories chart + if( bExportContent && + mbHasCategoryLabels ) + { + OUString aCategoriesRange; + // fill msString with cell-range-address of categories + // export own table references + if( xNewDiagram.is()) + { + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) ); + if( xCategories.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() ); + if( xValues.is()) + { + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + maCategoriesRange = xValues->getSourceRangeRepresentation(); + aCategoriesRange = lcl_ConvertRange( maCategoriesRange, xNewDoc ); + } + } + } + + if( aCategoriesRange.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, aCategoriesRange ); + SvXMLElementExport aCategories( mrExport, XML_NAMESPACE_CHART, XML_CATEGORIES, sal_True, sal_True ); + } + + // grid + Reference< beans::XPropertySet > xMajorGrid( xAxisXSupp->getXMainGrid(), uno::UNO_QUERY ); + if( bHasXAxisMajorGrid && xMajorGrid.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xMajorGrid ); + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, XML_MAJOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + Reference< beans::XPropertySet > xMinorGrid( xAxisXSupp->getXHelpGrid(), uno::UNO_QUERY ); + if( bHasXAxisMinorGrid && xMinorGrid.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xMinorGrid ); + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, XML_MINOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + if( pAxis ) + { + delete pAxis; + pAxis = NULL; + } + } + } + + // secondary x axis + if( bHasSecondaryXAxis || bHasSecondaryXAxisTitle ) + { + Reference< chart::XTwoAxisXSupplier > xAxisTwoXSupp( xDiagram, uno::UNO_QUERY ); + if( xAxisTwoXSupp.is()) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + xPropSet = xAxisTwoXSupp->getSecondaryXAxis(); + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, XML_X ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, XML_SECONDARY_X ); + AddAutoStyleAttribute( aPropertyStates ); + pAxis = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + + if( bHasSecondaryXAxisTitle ) + { + Reference< chart::XSecondAxisTitleSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xTitleProp( xAxisSupp->getSecondXAxisTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xTitleProp ); + if( bExportContent ) + { + OUString aText; + Any aAny( xTitleProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + aAny >>= aText; + + Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, sal_True, sal_True ); + + exportText( aText ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + } + + if( pAxis ) + { + delete pAxis; + pAxis = NULL; + } + } + } + + // y axis + // ------- + + // write axis element also if the axis itself is not visible, but a grid or + // title + Reference< chart::XAxisYSupplier > xAxisYSupp( xDiagram, uno::UNO_QUERY ); + if( xAxisYSupp.is()) + { + bool bHasAxisProperties = false; + // get property states for autostyles + if( mxExpPropMapper.is()) + { + xPropSet = xAxisYSupp->getYAxis(); + if( xPropSet.is()) + { + bHasAxisProperties = true; + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + } + + if( bHasYAxis || + bHasYAxisTitle || bHasYAxisMajorGrid || bHasYAxisMinorGrid || bHasAxisProperties ) + { + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, XML_Y ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, XML_PRIMARY_Y ); + AddAutoStyleAttribute( aPropertyStates ); + pAxis = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + + // axis-title + if( bHasYAxisTitle ) + { + Reference< beans::XPropertySet > xTitleProp( xAxisYSupp->getYAxisTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xTitleProp ); + if( bExportContent ) + { + OUString aText; + Any aAny( xTitleProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + aAny >>= aText; + + Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, sal_True, sal_True ); + + // paragraph containing title + exportText( aText ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + } + + // grid + Reference< beans::XPropertySet > xMajorGrid( xAxisYSupp->getYMainGrid(), uno::UNO_QUERY ); + if( bHasYAxisMajorGrid && xMajorGrid.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xMajorGrid ); + + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, XML_MAJOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + // minor grid + Reference< beans::XPropertySet > xMinorGrid( xAxisYSupp->getYHelpGrid(), uno::UNO_QUERY ); + if( bHasYAxisMinorGrid && xMinorGrid.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xMinorGrid ); + + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, XML_MINOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + if( pAxis ) + { + delete pAxis; + pAxis = NULL; + } + } + } + + if( bHasSecondaryYAxis || bHasSecondaryYAxisTitle ) + { + Reference< chart::XTwoAxisYSupplier > xAxisTwoYSupp( xDiagram, uno::UNO_QUERY ); + if( xAxisTwoYSupp.is()) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + xPropSet = xAxisTwoYSupp->getSecondaryYAxis(); + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, XML_Y ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, XML_SECONDARY_Y ); + AddAutoStyleAttribute( aPropertyStates ); + pAxis = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + if( bHasSecondaryYAxisTitle ) + { + Reference< chart::XSecondAxisTitleSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xTitleProp( xAxisSupp->getSecondYAxisTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xTitleProp ); + if( bExportContent ) + { + OUString aText; + Any aAny( xTitleProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + aAny >>= aText; + + Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, sal_True, sal_True ); + + exportText( aText ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + } + + if( pAxis ) + { + delete pAxis; + pAxis = NULL; + } + } + } + + // z axis + // ------- + + if( bHasZAxis && + bIs3DChart ) + { + Reference< chart::XAxisZSupplier > xAxisZSupp( xDiagram, uno::UNO_QUERY ); + if( xAxisZSupp.is()) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + xPropSet = xAxisZSupp->getZAxis(); + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, XML_Z ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, XML_PRIMARY_Z ); + + AddAutoStyleAttribute( aPropertyStates ); + pAxis = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + + // axis-title + if( bHasZAxisTitle ) + { + Reference< beans::XPropertySet > xTitleProp( xAxisZSupp->getZAxisTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xTitleProp ); + if( bExportContent ) + { + OUString aText; + Any aAny( xTitleProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )))); + aAny >>= aText; + + Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, sal_True, sal_True ); + + // paragraph containing title + exportText( aText ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + } + + // grid + Reference< beans::XPropertySet > xMajorGrid( xAxisZSupp->getZMainGrid(), uno::UNO_QUERY ); + if( bHasZAxisMajorGrid && xMajorGrid.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xMajorGrid ); + + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, XML_MAJOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + // minor grid + Reference< beans::XPropertySet > xMinorGrid( xAxisZSupp->getZHelpGrid(), uno::UNO_QUERY ); + if( bHasZAxisMinorGrid && xMinorGrid.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xMinorGrid ); + + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, XML_MINOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, sal_True, sal_True ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + } + } + if( pAxis ) + { + delete pAxis; + pAxis = NULL; + } + } +} + +void SchXMLExportHelper_Impl::exportSeries( + const Reference< chart2::XDiagram > & xNewDiagram, + const awt::Size & rPageSize, + sal_Bool bExportContent, + sal_Bool bHasTwoYAxes ) +{ + Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY ); + if( ! xBCooSysCnt.is()) + return; + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + + OUString aFirstXDomainRange; + OUString aFirstYDomainRange; + + std::vector< XMLPropertyState > aPropertyStates; + + const OUString sNumFormat( OUString::createFromAscii( "NumberFormat" )); + const OUString sPercentageNumFormat( OUString::createFromAscii( "PercentageNumberFormat" )); + + Sequence< Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xBCooSysCnt->getCoordinateSystems()); + for( sal_Int32 nCSIdx=0; nCSIdx<aCooSysSeq.getLength(); ++nCSIdx ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCSIdx], uno::UNO_QUERY ); + if( ! xCTCnt.is()) + continue; + Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); + for( sal_Int32 nCTIdx=0; nCTIdx<aCTSeq.getLength(); ++nCTIdx ) + { + Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nCTIdx], uno::UNO_QUERY ); + if( ! xDSCnt.is()) + continue; + // note: if xDSCnt.is() then also aCTSeq[nCTIdx] + OUString aChartType( aCTSeq[nCTIdx]->getChartType()); + OUString aLabelRole = aCTSeq[nCTIdx]->getRoleOfSequenceForSeriesLabel(); + + // special export for stock charts + if( aChartType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.CandleStickChartType"))) + { + sal_Bool bJapaneseCandleSticks = sal_False; + Reference< beans::XPropertySet > xCTProp( aCTSeq[nCTIdx], uno::UNO_QUERY ); + if( xCTProp.is()) + xCTProp->getPropertyValue( OUString::createFromAscii("Japanese")) >>= bJapaneseCandleSticks; + exportCandleStickSeries( + xDSCnt->getDataSeries(), xNewDiagram, bJapaneseCandleSticks, bExportContent ); + continue; + } + + // export dataseries for current chart-type + Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries()); + for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx ) + { + // export series + Reference< chart2::data::XDataSource > xSource( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ); + if( xSource.is()) + { + SvXMLElementExport* pSeries = NULL; + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + sal_Int32 nMainSequenceIndex = -1; + sal_Int32 nSeriesLength = 0; + sal_Int32 nAttachedAxis = chart::ChartAxisAssign::PRIMARY_Y; + sal_Bool bHasMeanValueLine = false; + chart::ChartRegressionCurveType eRegressionType( chart::ChartRegressionCurveType_NONE ); + chart::ChartErrorIndicatorType eErrorType( chart::ChartErrorIndicatorType_NONE ); + sal_Int32 nErrorBarStyle( chart::ErrorBarStyle::NONE ); + Reference< beans::XPropertySet > xPropSet; + tLabelValuesDataPair aSeriesLabelValuesPair; + + // search for main sequence and create a series element + { + Reference< chart2::data::XDataSequence > xValuesSeq; + Reference< chart2::data::XDataSequence > xLabelSeq; + sal_Int32 nSeqIdx=0; + for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx ) + { + OUString aRole; + Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() ); + if( nMainSequenceIndex==-1 ) + { + Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->getPropertyValue(OUString::createFromAscii("Role")) >>= aRole; + // "main" sequence + if( aRole.equals( aLabelRole )) + { + xValuesSeq.set( xTempValueSeq ); + xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel()); + nMainSequenceIndex = nSeqIdx; + } + } + sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0)); + if( nSeriesLength < nSequenceLength ) + nSeriesLength = nSequenceLength; + } + + // have found the main sequence, then xValuesSeq and + // xLabelSeq contain those. Otherwise both are empty + { + // get property states for autostyles + try + { + xPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet( + aSeriesSeq[nSeriesIdx], mrExport.GetModel() ); + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + OSL_TRACE( + OUStringToOString( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "Series not found or no XPropertySet: " )) + + rEx.Message, + RTL_TEXTENCODING_ASCII_US ).getStr()); + continue; + } + if( xPropSet.is()) + { + // determine attached axis + try + { + Any aAny( xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Axis" )))); + aAny >>= nAttachedAxis; + + aAny = xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM ( "MeanValue" ))); + aAny >>= bHasMeanValueLine; + + aAny = xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "RegressionCurves" ))); + aAny >>= eRegressionType; + + aAny = xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "ErrorIndicator" ))); + aAny >>= eErrorType; + + aAny = xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "ErrorBarStyle" ))); + aAny >>= nErrorBarStyle; + } + catch( beans::UnknownPropertyException & rEx ) + { + (void)rEx; // avoid warning for pro build + OSL_TRACE( + OUStringToOString( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "Required property not found in DataRowProperties: " )) + + rEx.Message, + RTL_TEXTENCODING_ASCII_US ).getStr()); + } + + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 ) + { + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + lcl_exportNumberFormat( sPercentageNumFormat, xPropSet, mrExport ); + } + + if( mxExpPropMapper.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + if( bHasTwoYAxes ) + { + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + } + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + if( xValuesSeq.is()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, + lcl_ConvertRange( + xValuesSeq->getSourceRangeRepresentation(), + xNewDoc )); + else + // #i75297# allow empty series, export empty range to have all ranges on import + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, OUString()); + + if( xLabelSeq.is()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, + lcl_ConvertRange( + xLabelSeq->getSourceRangeRepresentation(), + xNewDoc )); + if( xLabelSeq.is() || xValuesSeq.is() ) + aSeriesLabelValuesPair = tLabelValuesDataPair( xLabelSeq, xValuesSeq ); + + // chart-type for mixed types + enum XMLTokenEnum eCTToken( + SchXMLTools::getTokenByChartType( aChartType, false /* bUseOldNames */ )); + //@todo: get token for current charttype + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( eCTToken ))); + + // open series element until end of for loop + pSeries = new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_SERIES, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + } + + // export domain elements if we have a series parent element + if( pSeries ) + { + // domain elements + if( bExportContent ) + { + bool bIsScatterChart = aChartType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.ScatterChartType")); + bool bIsBubbleChart = aChartType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.BubbleChartType")); + Reference< chart2::data::XDataSequence > xYValuesForBubbleChart; + if( bIsBubbleChart ) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii("values-y" ) ) ); + if( xSequence.is() ) + { + xYValuesForBubbleChart = xSequence->getValues(); + if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart, aFirstYDomainRange, mrExport ) ) + xYValuesForBubbleChart = 0; + } + } + if( bIsScatterChart || bIsBubbleChart ) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii("values-x" ) ) ); + if( xSequence.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() ); + if( lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ) ) + m_aDataSequencesToExport.push_back( tLabelValuesDataPair( 0, xValues )); + } + } + if( xYValuesForBubbleChart.is() ) + m_aDataSequencesToExport.push_back( tLabelValuesDataPair( 0, xYValuesForBubbleChart )); + } + } + + // add sequences for main sequence after domain sequences, + // so that the export of the local table has the correct order + if( bExportContent && + (aSeriesLabelValuesPair.first.is() || aSeriesLabelValuesPair.second.is())) + m_aDataSequencesToExport.push_back( aSeriesLabelValuesPair ); + + // statistical objects: + // regression curves and mean value lines + if( bHasMeanValueLine && + xPropSet.is() && + mxExpPropMapper.is() ) + { + Reference< beans::XPropertySet > xStatProp; + try + { + Any aPropAny( xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMeanValueProperties" )))); + aPropAny >>= xStatProp; + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + DBG_ERROR1( "Exception caught during Export of series - optional DataMeanValueProperties not available: %s", + OUStringToOString( rEx.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } + + if( xStatProp.is() ) + { + aPropertyStates = mxExpPropMapper->Filter( xStatProp ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_MEAN_VALUE, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + + if( eRegressionType != chart::ChartRegressionCurveType_NONE && + xPropSet.is() && + mxExpPropMapper.is() ) + { + exportRegressionCurve( aSeriesSeq[nSeriesIdx], xPropSet, rPageSize, bExportContent ); + } + + if( nErrorBarStyle != chart::ErrorBarStyle::NONE && + eErrorType != chart::ChartErrorIndicatorType_NONE && + xPropSet.is() && + mxExpPropMapper.is() ) + { + Reference< beans::XPropertySet > xStatProp; + try + { + Any aPropAny( xPropSet->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "DataErrorProperties" )))); + aPropAny >>= xStatProp; + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + DBG_ERROR1( "Exception caught during Export of series - optional DataErrorProperties not available: %s", + OUStringToOString( rEx.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } + + if( xStatProp.is() ) + { + if( bExportContent && + nErrorBarStyle == chart::ErrorBarStyle::FROM_DATA ) + { + // register data ranges for error bars for export in local table + ::std::vector< Reference< chart2::data::XDataSequence > > aErrorBarSequences( + lcl_getErrorBarSequences( xStatProp )); + for( ::std::vector< Reference< chart2::data::XDataSequence > >::const_iterator aIt( + aErrorBarSequences.begin()); aIt != aErrorBarSequences.end(); ++aIt ) + { + m_aDataSequencesToExport.push_back( tLabelValuesDataPair( 0, *aIt )); + } + } + + aPropertyStates = mxExpPropMapper->Filter( xStatProp ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + const SvtSaveOptions::ODFDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentVersion >= SvtSaveOptions::ODFVER_012 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, XML_Y );//#i114149# + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, sal_True, sal_True ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + + exportDataPoints( + uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ), + nSeriesLength, xNewDiagram, bExportContent ); + + // close series element + if( pSeries ) + delete pSeries; + } + } + aPropertyStates.clear(); + } + } +} + +void SchXMLExportHelper_Impl::exportRegressionCurve( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< beans::XPropertySet > & xSeriesProp, + const awt::Size & rPageSize, + sal_Bool bExportContent ) +{ + OSL_ASSERT( mxExpPropMapper.is()); + + std::vector< XMLPropertyState > aPropertyStates; + std::vector< XMLPropertyState > aEquationPropertyStates; + Reference< beans::XPropertySet > xStatProp; + try + { + Any aPropAny( xSeriesProp->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "DataRegressionProperties" )))); + aPropAny >>= xStatProp; + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + DBG_ERROR1( "Exception caught during Export of series - optional DataRegressionProperties not available: %s", + OUStringToOString( rEx.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } + + if( xStatProp.is() ) + { + Reference< chart2::XRegressionCurve > xRegCurve( SchXMLTools::getRegressionCurve( xSeries )); + Reference< beans::XPropertySet > xEquationProperties; + if( xRegCurve.is()) + xEquationProperties.set( xRegCurve->getEquationProperties()); + + bool bShowEquation = false; + bool bShowRSquared = false; + bool bExportEquation = false; + aPropertyStates = mxExpPropMapper->Filter( xStatProp ); + if( xEquationProperties.is()) + { + xEquationProperties->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "ShowEquation" ))) + >>= bShowEquation; + xEquationProperties->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "ShowCorrelationCoefficient" ))) + >>= bShowRSquared; + bExportEquation = ( bShowEquation || bShowRSquared ); + const SvtSaveOptions::ODFDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentVersion < SvtSaveOptions::ODFVER_012 ) + bExportEquation=false; + if( bExportEquation ) + { + // number format + sal_Int32 nNumberFormat = 0; + if( ( xEquationProperties->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "NumberFormat" ))) >>= nNumberFormat ) && + nNumberFormat != -1 ) + { + mrExport.addDataStyle( nNumberFormat ); + } + aEquationPropertyStates = mxExpPropMapper->Filter( xEquationProperties ); + } + } + + if( !aPropertyStates.empty() || bExportEquation ) + { + // write element + if( bExportContent ) + { + // add style name attribute + if( !aPropertyStates.empty()) + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aRegressionExport( mrExport, XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, sal_True, sal_True ); + if( bExportEquation ) + { + // default is true + if( !bShowEquation ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_EQUATION, XML_FALSE ); + // default is false + if( bShowRSquared ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, XML_TRUE ); + + // export position + chart2::RelativePosition aRelativePosition; + if( xEquationProperties->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM("RelativePosition"))) >>= aRelativePosition ) + { + double fX = aRelativePosition.Primary * rPageSize.Width; + double fY = aRelativePosition.Secondary * rPageSize.Height; + awt::Point aPos; + aPos.X = static_cast< sal_Int32 >( ::rtl::math::round( fX )); + aPos.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY )); + addPosition( aPos ); + } + + if( !aEquationPropertyStates.empty()) + AddAutoStyleAttribute( aEquationPropertyStates ); + + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_EQUATION, sal_True, sal_True ); + } + } + else // autostyles + { + if( !aPropertyStates.empty()) + CollectAutoStyle( aPropertyStates ); + if( bExportEquation && !aEquationPropertyStates.empty()) + CollectAutoStyle( aEquationPropertyStates ); + } + } + } +} + +void SchXMLExportHelper_Impl::exportCandleStickSeries( + const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq, + const Reference< chart2::XDiagram > & xDiagram, + sal_Bool bJapaneseCandleSticks, + sal_Bool bExportContent ) +{ +// std::vector< XMLPropertyState > aPropertyStates; + + for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx ) + { + Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nSeriesIdx] ); + sal_Int32 nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries ) + ? chart::ChartAxisAssign::PRIMARY_Y + : chart::ChartAxisAssign::SECONDARY_Y; + + Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + // export series in correct order (as we don't store roles) + // with japanese candlesticks: open, low, high, close + // otherwise: low, high, close + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + + sal_Int32 nSeriesLength = + lcl_getSequenceLengthByRole( aSeqCnt, OUString::createFromAscii("values-last")); + + if( bExportContent ) + { + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + //@todo: export data points + + // open + if( bJapaneseCandleSticks ) + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, OUString::createFromAscii("values-first"), xNewDoc, m_aDataSequencesToExport )); + if( aRanges.second.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( aRanges.first.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aOpenSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, sal_True, sal_True ); + // export empty data points + exportDataPoints( 0, nSeriesLength, xDiagram, bExportContent ); + } + + // low + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, OUString::createFromAscii("values-min"), xNewDoc, m_aDataSequencesToExport )); + if( aRanges.second.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( aRanges.first.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aLowSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, sal_True, sal_True ); + // export empty data points + exportDataPoints( 0, nSeriesLength, xDiagram, bExportContent ); + } + + // high + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, OUString::createFromAscii("values-max"), xNewDoc, m_aDataSequencesToExport )); + if( aRanges.second.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( aRanges.first.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aHighSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, sal_True, sal_True ); + // export empty data points + exportDataPoints( 0, nSeriesLength, xDiagram, bExportContent ); + } + + // close + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, OUString::createFromAscii("values-last"), xNewDoc, m_aDataSequencesToExport )); + if( aRanges.second.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( aRanges.first.getLength()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + // write style name +// AddAutoStyleAttribute( aPropertyStates ); + // chart type +// mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, +// mrExport.GetNamespaceMap().GetQNameByKey( +// XML_NAMESPACE_CHART, GetXMLToken( XML_STOCK ))); + SvXMLElementExport aCloseSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, sal_True, sal_True ); + // export empty data points + exportDataPoints( 0, nSeriesLength, xDiagram, bExportContent ); + } + } + else // autostyles + { + // for close series +// CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles +// aPropertyStates.clear(); + } + } +} + +void SchXMLExportHelper_Impl::exportDataPoints( + const uno::Reference< beans::XPropertySet > & xSeriesProperties, + sal_Int32 nSeriesLength, + const uno::Reference< chart2::XDiagram > & xDiagram, + sal_Bool bExportContent ) +{ + // data-points + // ----------- + // write data-points only if they contain autostyles + // objects with equal autostyles are grouped using the attribute + // repeat="number" + + // Note: if only the nth data-point has autostyles there is an element + // without style and repeat="n-1" attribute written in advance. + + // the sequence aDataPointSeq contains indices of data-points that + // do have own attributes. This increases the performance substantially. + + // more performant version for #93600# + if( mxExpPropMapper.is()) + { + uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY ); + + std::vector< XMLPropertyState > aPropertyStates; + + const OUString sNumFormat( OUString::createFromAscii( "NumberFormat" )); + const OUString sPercentageNumFormat( OUString::createFromAscii( "PercentageNumberFormat" )); + + bool bVaryColorsByPoint = false; + Sequence< sal_Int32 > aDataPointSeq; + if( xSeriesProperties.is()) + { + Any aAny = xSeriesProperties->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "AttributedDataPoints" ))); + aAny >>= aDataPointSeq; + xSeriesProperties->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM( "VaryColorsByPoint" ))) >>= bVaryColorsByPoint; + } + + + sal_Int32 nSize = aDataPointSeq.getLength(); + DBG_ASSERT( nSize <= nSeriesLength, "Too many point attributes" ); + + const sal_Int32 * pPoints = aDataPointSeq.getConstArray(); + sal_Int32 nElement; + sal_Int32 nRepeat; + Reference< chart2::XColorScheme > xColorScheme; + if( xDiagram.is()) + xColorScheme.set( xDiagram->getDefaultColorScheme()); + + ::std::list< SchXMLDataPointStruct > aDataPointList; + + sal_Int32 nLastIndex = -1; + sal_Int32 nCurrIndex = 0; + + // collect elements + if( bVaryColorsByPoint && xColorScheme.is() ) + { + ::std::set< sal_Int32 > aAttrPointSet; + ::std::copy( pPoints, pPoints + aDataPointSeq.getLength(), + ::std::inserter( aAttrPointSet, aAttrPointSet.begin())); + const ::std::set< sal_Int32 >::const_iterator aEndIt( aAttrPointSet.end()); + for( nElement = 0; nElement < nSeriesLength; ++nElement ) + { + aPropertyStates.clear(); + uno::Reference< beans::XPropertySet > xPropSet; + bool bExportNumFmt = false; + if( aAttrPointSet.find( nElement ) != aEndIt ) + { + try + { + xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + xSeries, nElement, mrExport.GetModel() ); + bExportNumFmt = true; + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + DBG_ERROR1( "Exception caught during Export of data point: %s", + OUStringToOString( rEx.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } + } + else + { + // property set only containing the color + xPropSet.set( new ::xmloff::chart::ColorPropertySet( + xColorScheme->getColorByIndex( nElement ))); + } + DBG_ASSERT( xPropSet.is(), "Pie Segments should have properties" ); + if( xPropSet.is()) + { + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 && bExportNumFmt ) + { + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + lcl_exportNumberFormat( sPercentageNumFormat, xPropSet, mrExport ); + } + + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + // write data-point with style + DBG_ASSERT( ! maAutoStyleNameQueue.empty(), "Autostyle queue empty!" ); + + SchXMLDataPointStruct aPoint; + aPoint.maStyleName = maAutoStyleNameQueue.front(); + maAutoStyleNameQueue.pop(); + aDataPointList.push_back( aPoint ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + DBG_ASSERT( !bExportContent || (static_cast<sal_Int32>(aDataPointList.size()) == nSeriesLength), + "not enough data points on content export" ); + } + else + { + for( nElement = 0; nElement < nSize; ++nElement ) + { + aPropertyStates.clear(); + nCurrIndex = pPoints[ nElement ]; + //assuming sorted indices in pPoints + + if( nCurrIndex<0 || nCurrIndex>=nSeriesLength ) + break; + + // write leading empty data points + if( nCurrIndex - nLastIndex > 1 ) + { + SchXMLDataPointStruct aPoint; + aPoint.mnRepeat = nCurrIndex - nLastIndex - 1; + aDataPointList.push_back( aPoint ); + } + + uno::Reference< beans::XPropertySet > xPropSet; + // get property states + try + { + xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + xSeries, nCurrIndex, mrExport.GetModel() ); + } + catch( uno::Exception & rEx ) + { + (void)rEx; // avoid warning for pro build + DBG_ERROR1( "Exception caught during Export of data point: %s", + OUStringToOString( rEx.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } + if( xPropSet.is()) + { + const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); + if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 ) + { + lcl_exportNumberFormat( sNumFormat, xPropSet, mrExport ); + lcl_exportNumberFormat( sPercentageNumFormat, xPropSet, mrExport ); + } + + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + // write data-point with style + DBG_ASSERT( ! maAutoStyleNameQueue.empty(), "Autostyle queue empty!" ); + SchXMLDataPointStruct aPoint; + aPoint.maStyleName = maAutoStyleNameQueue.front(); + maAutoStyleNameQueue.pop(); + + aDataPointList.push_back( aPoint ); + nLastIndex = nCurrIndex; + } + else + { + CollectAutoStyle( aPropertyStates ); + } + continue; + } + } + + // if we get here the property states are empty + SchXMLDataPointStruct aPoint; + aDataPointList.push_back( aPoint ); + + nLastIndex = nCurrIndex; + } + // final empty elements + nRepeat = nSeriesLength - nLastIndex - 1; + if( nRepeat > 0 ) + { + SchXMLDataPointStruct aPoint; + aPoint.mnRepeat = nRepeat; + aDataPointList.push_back( aPoint ); + } + } + + if( bExportContent ) + { + // write elements (merge equal ones) + ::std::list< SchXMLDataPointStruct >::iterator aIter = aDataPointList.begin(); + SchXMLDataPointStruct aPoint; + SchXMLDataPointStruct aLastPoint; + + // initialize so that it doesn't matter if + // the element is counted in the first iteration + aLastPoint.mnRepeat = 0; + + for( ; aIter != aDataPointList.end(); ++aIter ) + { + aPoint = (*aIter); + + if( aPoint.maStyleName == aLastPoint.maStyleName ) + aPoint.mnRepeat += aLastPoint.mnRepeat; + else if( aLastPoint.mnRepeat > 0 ) + { + // write last element + if( aLastPoint.maStyleName.getLength() ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); + + if( aLastPoint.mnRepeat > 1 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED, + OUString::valueOf( (sal_Int64)( aLastPoint.mnRepeat ) )); + + SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, sal_True, sal_True ); + } + aLastPoint = aPoint; + } + // write last element if it hasn't been written in last iteration + if( aPoint.maStyleName == aLastPoint.maStyleName ) + { + if( aLastPoint.maStyleName.getLength() ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); + + if( aLastPoint.mnRepeat > 1 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED, + OUString::valueOf( (sal_Int64)( aLastPoint.mnRepeat ) )); + + SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, sal_True, sal_True ); + } + } + } +} + + +void SchXMLExportHelper_Impl::getCellAddress( sal_Int32 nCol, sal_Int32 nRow ) +{ + msStringBuffer.append( (sal_Unicode)'.' ); + if( nCol < 26 ) + msStringBuffer.append( (sal_Unicode)('A' + nCol) ); + else if( nCol < 702 ) + { + msStringBuffer.append( (sal_Unicode)('A' + nCol / 26 - 1 )); + msStringBuffer.append( (sal_Unicode)('A' + nCol % 26) ); + } + else + { + msStringBuffer.append( (sal_Unicode)('A' + nCol / 702 - 1 )); + msStringBuffer.append( (sal_Unicode)('A' + (nCol % 702) / 26 )); + msStringBuffer.append( (sal_Unicode)('A' + nCol % 26) ); + } + + msStringBuffer.append( nRow + (sal_Int32)1 ); +} + +void SchXMLExportHelper_Impl::addPosition( const awt::Point & rPosition ) +{ + mrExport.GetMM100UnitConverter().convertMeasure( msStringBuffer, rPosition.X ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, msString ); + + mrExport.GetMM100UnitConverter().convertMeasure( msStringBuffer, rPosition.Y ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, msString ); +} + +void SchXMLExportHelper_Impl::addPosition( Reference< drawing::XShape > xShape ) +{ + if( xShape.is()) + addPosition( xShape->getPosition()); +} + +void SchXMLExportHelper_Impl::addSize( const awt::Size & rSize ) +{ + mrExport.GetMM100UnitConverter().convertMeasure( msStringBuffer, rSize.Width ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, msString ); + + mrExport.GetMM100UnitConverter().convertMeasure( msStringBuffer, rSize.Height ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, msString ); +} + +void SchXMLExportHelper_Impl::addSize( Reference< drawing::XShape > xShape ) +{ + if( xShape.is()) + addSize( xShape->getSize() ); +} + +awt::Size SchXMLExportHelper_Impl::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc ) const +{ + awt::Size aSize( 8000, 7000 ); + uno::Reference< embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY ); + DBG_ASSERT( xVisualObject.is(),"need XVisualObject for page size" ); + if( xVisualObject.is() ) + aSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); + + return aSize; +} + +void SchXMLExportHelper_Impl::CollectAutoStyle( const std::vector< XMLPropertyState >& aStates ) +{ + if( !aStates.empty() ) + maAutoStyleNameQueue.push( GetAutoStylePoolP().Add( XML_STYLE_FAMILY_SCH_CHART_ID, aStates )); +} + +void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates ) +{ + if( !aStates.empty() ) + { + DBG_ASSERT( ! maAutoStyleNameQueue.empty(), "Autostyle queue empty!" ); + + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, maAutoStyleNameQueue.front() ); + maAutoStyleNameQueue.pop(); + } +} + +void SchXMLExportHelper_Impl::exportText( const OUString& rText, bool bConvertTabsLFs ) +{ + SchXMLTools::exportText( mrExport, rText, bConvertTabsLFs ); +} + +// ======================================== +// class SchXMLExport +// ======================================== + +// #110680# +SchXMLExport::SchXMLExport( + const Reference< lang::XMultiServiceFactory >& xServiceFactory, + sal_uInt16 nExportFlags ) +: SvXMLExport( xServiceFactory, MAP_CM, ::xmloff::token::XML_CHART, nExportFlags ), + maAutoStylePool( *this ), + maExportHelper( *this, maAutoStylePool ) +{ + if( getDefaultVersion() == SvtSaveOptions::ODFVER_LATEST ) + _GetNamespaceMap().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT); +} + + +SchXMLExport::~SchXMLExport() +{ + // stop progress view + if( mxStatusIndicator.is()) + { + mxStatusIndicator->end(); + mxStatusIndicator->reset(); + } +} + +sal_uInt32 SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ) +{ + Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + maExportHelper.m_pImpl->InitRangeSegmentationProperties( xChartDoc ); + return SvXMLExport::exportDoc( eClass ); +} + +void SchXMLExport::_ExportStyles( sal_Bool bUsed ) +{ + SvXMLExport::_ExportStyles( bUsed ); +} + +void SchXMLExport::_ExportMasterStyles() +{ + // not available in chart + DBG_WARNING( "Master Style Export requested. Not available for Chart" ); +} + +void SchXMLExport::_ExportAutoStyles() +{ + // there are no styles that require their own autostyles + if( getExportFlags() & EXPORT_CONTENT ) + { + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + maExportHelper.m_pImpl->collectAutoStyles( xChartDoc ); + maExportHelper.m_pImpl->exportAutoStyles(); + } + else + { + DBG_ERROR( "Couldn't export chart due to wrong XModel (must be XChartDocument)" ); + } + } +} + +void SchXMLExport::_ExportContent() +{ + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + // determine if data comes from the outside + sal_Bool bIncludeTable = sal_True; + + Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY ); + if( xNewDoc.is()) + { + // check if we have own data. If so we must not export the complete + // range string, as this is our only indicator for having own or + // external data. @todo: fix this in the file format! + Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + if( ! (xDPServiceInfo.is() && + xDPServiceInfo->getImplementationName().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "com.sun.star.comp.chart.InternalDataProvider" )))) + { + bIncludeTable = sal_False; + } + } + else + { + Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY ); + if( xServ.is()) + { + if( xServ->supportsService( + OUString::createFromAscii( "com.sun.star.chart.ChartTableAddressSupplier" ))) + { + Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY ); + if( xProp.is()) + { + Any aAny; + try + { + OUString sChartAddress; + aAny = xProp->getPropertyValue( + OUString::createFromAscii( "ChartRangeAddress" )); + aAny >>= sChartAddress; + maExportHelper.m_pImpl->SetChartRangeAddress( sChartAddress ); + + OUString sTableNumberList; + aAny = xProp->getPropertyValue( + OUString::createFromAscii( "TableNumberList" )); + aAny >>= sTableNumberList; + maExportHelper.m_pImpl->SetTableNumberList( sTableNumberList ); + + // do not include own table if there are external addresses + bIncludeTable = (sChartAddress.getLength() == 0); + } + catch( beans::UnknownPropertyException & ) + { + DBG_ERROR( "Property ChartRangeAddress not supported by ChartDocument" ); + } + } + } + } + } + maExportHelper.m_pImpl->exportChart( xChartDoc, bIncludeTable ); + } + else + { + DBG_ERROR( "Couldn't export chart due to wrong XModel" ); + } +} + +void SchXMLExport::SetProgress( sal_Int32 nPercentage ) +{ + // set progress view + if( mxStatusIndicator.is()) + mxStatusIndicator->setValue( nPercentage ); +} + +UniReference< XMLPropertySetMapper > SchXMLExport::GetPropertySetMapper() const +{ + return maExportHelper.m_pImpl->GetPropertySetMapper(); +} + +void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc ) +{ + if( xChartDoc.is()) + try + { + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + OSL_ENSURE( xDataProvider.is(), "No DataProvider" ); + if( xDataProvider.is()) + { + Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels )); + Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource )); + ::rtl::OUString sCellRange, sBrokenRange; + bool bBrokenRangeAvailable = false; + for( sal_Int32 i=0; i<aArgs.getLength(); ++i ) + { + if( aArgs[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CellRangeRepresentation"))) + aArgs[i].Value >>= sCellRange; + else if( aArgs[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("BrokenCellRangeForExport"))) + { + if( aArgs[i].Value >>= sBrokenRange ) + bBrokenRangeAvailable = true; + } + else if( aArgs[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("DataRowSource"))) + { + chart::ChartDataRowSource eRowSource; + aArgs[i].Value >>= eRowSource; + mbRowSourceColumns = ( eRowSource == chart::ChartDataRowSource_COLUMNS ); + } + else if( aArgs[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FirstCellAsLabel"))) + aArgs[i].Value >>= mbHasSeriesLabels; + else if( aArgs[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("SequenceMapping"))) + aArgs[i].Value >>= maSequenceMapping; + else if( aArgs[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("TableNumberList"))) + aArgs[i].Value >>= msTableNumberList; + } + + // #i79009# For Writer we have to export a broken version of the + // range, where every row number is noe too large, so that older + // version can correctly read those files. + msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange); + if( msChartAddress.getLength() > 0 ) + { + // convert format to XML-conform one + Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY ); + if( xConversion.is()) + msChartAddress = xConversion->convertRangeToXML( msChartAddress ); + } + } + } + catch( uno::Exception & ex ) + { + (void)ex; // avoid warning for pro build + OSL_ENSURE( false, OUStringToOString( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught. Type: " )) + + OUString::createFromAscii( typeid( ex ).name()) + + OUString( RTL_CONSTASCII_USTRINGPARAM( ", Message: " )) + + ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr()); + } +} + +// export components ======================================== + +// first version: everything goes in one storage + +Sequence< OUString > SAL_CALL SchXMLExport_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLExporter" ) ); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Compact" ) ); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +{ + // #110680# + // #103997# removed some flags from EXPORT_ALL + // return (cppu::OWeakObject*)new SchXMLExport( EXPORT_ALL ^ ( EXPORT_SETTINGS | EXPORT_MASTERSTYLES | EXPORT_SCRIPTS )); + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, EXPORT_ALL ^ ( EXPORT_SETTINGS | EXPORT_MASTERSTYLES | EXPORT_SCRIPTS )); +} + +// Oasis format +Sequence< OUString > SAL_CALL SchXMLExport_Oasis_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLOasisExporter" ) ); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_Oasis_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Oasis.Compact" ) ); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_Oasis_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +{ + // #103997# removed some flags from EXPORT_ALL + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, + (EXPORT_ALL ^ ( EXPORT_SETTINGS | EXPORT_MASTERSTYLES | EXPORT_SCRIPTS )) | EXPORT_OASIS ); +} + +// ============================================================ + +// multiple storage version: one for content / styles / meta + +Sequence< OUString > SAL_CALL SchXMLExport_Styles_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLStylesExporter" )); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_Styles_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Styles" )); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_Styles_createInstance(const Reference< lang::XMultiServiceFactory >& rSMgr) throw( uno::Exception ) +{ + // #110680# + // return (cppu::OWeakObject*)new SchXMLExport( EXPORT_STYLES ); + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, EXPORT_STYLES ); +} + +// Oasis format +Sequence< OUString > SAL_CALL SchXMLExport_Oasis_Styles_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLOasisStylesExporter" )); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_Oasis_Styles_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Oasis.Styles" )); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_Oasis_Styles_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +{ + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, EXPORT_STYLES | EXPORT_OASIS ); +} + +// ------------------------------------------------------------ + +Sequence< OUString > SAL_CALL SchXMLExport_Content_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLContentExporter" )); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_Content_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Content" )); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_Content_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +{ + // #110680# + // return (cppu::OWeakObject*)new SchXMLExport( EXPORT_AUTOSTYLES | EXPORT_CONTENT | EXPORT_FONTDECLS ); + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, EXPORT_AUTOSTYLES | EXPORT_CONTENT | EXPORT_FONTDECLS ); +} + +// Oasis format +Sequence< OUString > SAL_CALL SchXMLExport_Oasis_Content_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLOasisContentExporter" )); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_Oasis_Content_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Oasis.Content" )); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_Oasis_Content_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +{ + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, EXPORT_AUTOSTYLES | EXPORT_CONTENT | EXPORT_FONTDECLS | EXPORT_OASIS ); +} + +// ------------------------------------------------------------ + +// Sequence< OUString > SAL_CALL SchXMLExport_Meta_getSupportedServiceNames() throw() +// { +// const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLMetaExporter" )); +// const Sequence< OUString > aSeq( &aServiceName, 1 ); +// return aSeq; +// } + +// OUString SAL_CALL SchXMLExport_Meta_getImplementationName() throw() +// { +// return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Meta" )); +// } + +// Reference< uno::XInterface > SAL_CALL SchXMLExport_Meta_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +// { +// return (cppu::OWeakObject*)new SchXMLExport( EXPORT_META ); +// } + +// Oasis format +Sequence< OUString > SAL_CALL SchXMLExport_Oasis_Meta_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Chart.XMLOasisMetaExporter" )); + const Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +OUString SAL_CALL SchXMLExport_Oasis_Meta_getImplementationName() throw() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SchXMLExport.Oasis.Meta" )); +} + +Reference< uno::XInterface > SAL_CALL SchXMLExport_Oasis_Meta_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr) throw( uno::Exception ) +{ + return (cppu::OWeakObject*)new SchXMLExport( rSMgr, EXPORT_META | EXPORT_OASIS ); +} + + +// XServiceInfo +OUString SAL_CALL SchXMLExport::getImplementationName() throw( uno::RuntimeException ) +{ + switch( getExportFlags()) + { + case EXPORT_ALL: + return SchXMLExport_getImplementationName(); + case EXPORT_STYLES: + return SchXMLExport_Styles_getImplementationName(); + case ( EXPORT_AUTOSTYLES | EXPORT_CONTENT | EXPORT_FONTDECLS ): + return SchXMLExport_Content_getImplementationName(); +// case EXPORT_META: +// return SchXMLExport_Meta_getImplementationName(); + + // Oasis format + case ( EXPORT_ALL | EXPORT_OASIS ): + return SchXMLExport_Oasis_getImplementationName(); + case ( EXPORT_STYLES | EXPORT_OASIS ): + return SchXMLExport_Oasis_Styles_getImplementationName(); + case ( EXPORT_AUTOSTYLES | EXPORT_CONTENT | EXPORT_FONTDECLS | EXPORT_OASIS ): + return SchXMLExport_Oasis_Content_getImplementationName(); + case ( EXPORT_META | EXPORT_OASIS ): + return SchXMLExport_Oasis_Meta_getImplementationName(); + + case EXPORT_SETTINGS: + // there is no settings component in chart + default: + return OUString::createFromAscii( "SchXMLExport" ); + } +} |