Files
libreoffice/oox/source/export/chartexport.cxx
Markus Mohrhard 010f58c4ef overlap is only valid for the 2D bar chart, related fdo#59857
Change-Id: Ie17ef54a2b2f2058cef97dacd9110a3065f76f68
2013-05-05 19:44:26 +02:00

2765 lines
97 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <oox/token/tokens.hxx>
#include "oox/core/xmlfilterbase.hxx"
#include "oox/export/chartexport.hxx"
#include "oox/export/utils.hxx"
#include "oox/drawingml/chart/typegroupconverter.hxx"
#include <cstdio>
#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/XChartDataArray.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/ChartSymbolType.hpp>
#include <com/sun/star/chart/ChartAxisMarks.hpp>
#include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
#include <com/sun/star/chart/ChartAxisPosition.hpp>
#include <com/sun/star/chart/ChartSolidType.hpp>
#include <com/sun/star/chart/DataLabelPlacement.hpp>
#include <com/sun/star/chart/ErrorBarStyle.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/DataPointGeometry3D.hpp>
#include <com/sun/star/chart2/DataPointLabel.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/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/BitmapMode.hpp>
#include <com/sun/star/table/CellAddress.hpp>
#include <com/sun/star/sheet/XFormulaParser.hpp>
#include <com/sun/star/sheet/XFormulaTokens.hpp>
#include <com/sun/star/sheet/FormulaToken.hpp>
#include <com/sun/star/sheet/AddressConvention.hpp>
#include <com/sun/star/text/WritingMode.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <comphelper/processfactory.hxx>
#include <xmloff/SchXMLSeriesHelper.hxx>
#include "ColorPropertySet.hxx"
#include <set>
#include <time.h>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::drawing;
using namespace ::oox::core;
using ::com::sun::star::beans::PropertyState;
using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::beans::XPropertyState;
using ::com::sun::star::container::XEnumeration;
using ::com::sun::star::container::XEnumerationAccess;
using ::com::sun::star::container::XIndexAccess;
using ::com::sun::star::container::XNamed;
using ::com::sun::star::io::XOutputStream;
using ::com::sun::star::table::CellAddress;
using ::com::sun::star::sheet::XFormulaParser;
using ::com::sun::star::sheet::XFormulaTokens;
using ::oox::core::XmlFilterBase;
using ::sax_fastparser::FSHelperPtr;
namespace cssc = com::sun::star::chart;
DBG(extern void dump_pset(Reference< XPropertySet > rXPropSet));
namespace oox { namespace drawingml {
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( "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 ));
}
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( const uno::Exception & ex )
{
(void)ex; // avoid warning for pro build
OSL_FAIL( OUStringToOString(
OUString( "Exception caught. Type: " ) +
OUString::createFromAscii( typeid( ex ).name()) +
OUString( ", Message: " ) +
ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
}
return xResult;
}
Reference< chart2::data::XDataSource > lcl_createDataSource(
const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData )
{
Reference< uno::XComponentContext > xContext(
comphelper::getProcessComponentContext() );
Reference< chart2::data::XDataSink > xSink(
xContext->getServiceManager()->createInstanceWithContext(
"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("values-x") ) );
if( xXValues.is() )
aLabeledSeqVector.push_back( xXValues );
//add all other sequences now without x-values
lcl_MatchesRole aHasXValues( OUString("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( "AttachedAxisIndex" ) ) >>= nAxisIndex;
bResult = (0==nAxisIndex);
}
catch( const uno::Exception & ex )
{
(void)ex; // avoid warning for pro build
OSL_FAIL( OUStringToOString(
OUString( "Exception caught. Type: " ) +
OUString::createFromAscii( typeid( ex ).name()) +
OUString( ", Message: " ) +
ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
}
return bResult;
}
OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
{
OUStringBuffer aResult;
bool bPrecedeWithSpace = false;
for( sal_Int32 nIndex=0; nIndex<rSequence.getLength(); ++nIndex )
{
if( !rSequence[nIndex].isEmpty())
{
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 );
}
void lcl_fillCategoriesIntoStringVector(
const Reference< chart2::data::XDataSequence > & xCategories,
::std::vector< OUString > & rOutCategories )
{
OSL_ASSERT( xCategories.is());
if( !xCategories.is())
return;
Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xCategories, uno::UNO_QUERY );
if( xTextualDataSequence.is())
{
rOutCategories.clear();
Sequence< OUString > aTextData( xTextualDataSequence->getTextualData());
::std::copy( aTextData.getConstArray(), aTextData.getConstArray() + aTextData.getLength(),
::std::back_inserter( rOutCategories ));
}
else
{
Sequence< uno::Any > aAnies( xCategories->getData());
rOutCategories.resize( aAnies.getLength());
for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
aAnies[i] >>= rOutCategories[i];
}
}
::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;
}
sal_Int32 lcl_getChartType( const OUString& sChartType )
{
chart::TypeId eChartTypeId = chart::TYPEID_UNKNOWN;
if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.BarDiagram" ))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.ColumnChartType" )))
eChartTypeId = chart::TYPEID_BAR;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.AreaDiagram" ))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.AreaChartType" ) ) )
eChartTypeId = chart::TYPEID_AREA;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.LineDiagram" ))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.LineChartType" ) ) )
eChartTypeId = chart::TYPEID_LINE;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.PieDiagram" ))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.PieChartType") ) )
eChartTypeId = chart::TYPEID_PIE;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.DonutDiagram"))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.DonutChartType") ) )
eChartTypeId = chart::TYPEID_DOUGHNUT;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.XYDiagram"))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.ScatterChartType") ) )
eChartTypeId = chart::TYPEID_SCATTER;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.NetDiagram"))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.NetChartType") ) )
eChartTypeId = chart::TYPEID_RADARLINE;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.FilledNetDiagram"))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.FilledNetChartType") ) )
eChartTypeId = chart::TYPEID_RADARAREA;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.StockDiagram"))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.CandleStickChartType") ) )
eChartTypeId = chart::TYPEID_STOCK;
else if(( 0 == sChartType.reverseCompareTo( "com.sun.star.chart.BubbleDiagram"))
|| ( 0 == sChartType.reverseCompareTo( "com.sun.star.chart2.BubbleChartType") ) )
eChartTypeId = chart::TYPEID_BUBBLE;
return eChartTypeId;
}
sal_Int32 lcl_generateRandomValue()
{
static sal_Int32 MAX_NUMBER = 100000000;
//srand( unsigned( time( NULL ) ));
return sal_Int32( rand() % MAX_NUMBER );
}
ChartExport::ChartExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, Reference< frame::XModel >& xModel, XmlFilterBase* pFB, DocumentType eDocumentType )
: DrawingML( pFS, pFB, eDocumentType )
, mnXmlNamespace( nXmlNamespace )
, maFraction( 1, 576 )
, mxChartModel( xModel )
, mbHasCategoryLabels( sal_False )
, mbHasZAxis( sal_False )
, mbIs3DChart( sal_False )
{
}
sal_Int32 ChartExport::GetChartID( )
{
sal_Int32 nID = GetFB()->GetUniqueId();
return nID;
}
sal_Int32 ChartExport::getChartType( )
{
OUString sChartType = mxDiagram->getDiagramType();
return lcl_getChartType( sChartType );
}
OUString ChartExport::parseFormula( const OUString& rRange )
{
OUString aResult;
Reference< XFormulaParser > xParser;
uno::Reference< lang::XMultiServiceFactory > xSF( GetFB()->getModelFactory(), uno::UNO_QUERY );
if( xSF.is() )
{
try
{
xParser.set( xSF->createInstance( OUString("com.sun.star.sheet.FormulaParser") ), UNO_QUERY );
}
catch( Exception& )
{
}
}
if( xParser.is() )
{
OSL_TRACE("ChartExport::parseFormula, parser is valid");
Reference< XPropertySet > xParserProps( xParser, uno::UNO_QUERY );
if( xParserProps.is() )
{
xParserProps->setPropertyValue( OUString("FormulaConvention"), uno::makeAny(::com::sun::star::sheet::AddressConvention::OOO) );
}
uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( rRange, CellAddress( 0, 0, 0 ) );
if( xParserProps.is() )
{
xParserProps->setPropertyValue( OUString("FormulaConvention"), uno::makeAny(::com::sun::star::sheet::AddressConvention::XL_OOX) );
}
aResult = xParser->printFormula( aTokens, CellAddress( 0, 0, 0 ) );
}
else
{
OSL_TRACE("ChartExport::parseFormula, parser is invalid");
//FIXME: currently just using simple converter, e.g $Sheet1.$A$1:$C$1 -> Sheet1!$A$1:$C$1
OUString aRange( rRange );
if( aRange.indexOf("$") == 0 )
aRange = aRange.copy(1);
aRange = aRange.replaceAll(".$", "!$" );
aResult = aRange;
}
OSL_TRACE("ChartExport::parseFormula, the originla formula is %s, the new formula is %s ", OUStringToOString( rRange, RTL_TEXTENCODING_UTF8 ).getStr(), OUStringToOString( aResult, RTL_TEXTENCODING_UTF8 ).getStr());
return aResult;
}
ChartExport& ChartExport::WriteChartObj( const Reference< XShape >& xShape, sal_Int32 nChartCount )
{
OSL_TRACE("ChartExport::WriteChartObj -- writer chart object");
FSHelperPtr pFS = GetFS();
pFS->startElementNS( mnXmlNamespace, XML_graphicFrame, FSEND );
pFS->startElementNS( mnXmlNamespace, XML_nvGraphicFramePr, FSEND );
// TODO: get the correct chart name chart id
OUString sName = "Object 1";
Reference< XNamed > xNamed( xShape, UNO_QUERY );
if (xNamed.is())
sName = xNamed->getName();
sal_Int32 nID = GetChartID();
pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
XML_id, I32S( nID ),
XML_name, USS( sName ),
FSEND );
pFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr,
FSEND );
if( GetDocumentType() == DOCUMENT_PPTX )
pFS->singleElementNS( mnXmlNamespace, XML_nvPr,
FSEND );
pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
// visual chart properties
WriteShapeTransformation( xShape, mnXmlNamespace );
// writer chart object
pFS->startElement( FSNS( XML_a, XML_graphic ), FSEND );
pFS->startElement( FSNS( XML_a, XML_graphicData ),
XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart",
FSEND );
OUString sId;
const char* sFullPath = NULL;
const char* sRelativePath = NULL;
switch( GetDocumentType() )
{
case DOCUMENT_DOCX:
{
sFullPath = "word/charts/chart";
sRelativePath = "charts/chart";
break;
}
case DOCUMENT_PPTX:
{
sFullPath = "ppt/charts/chart";
sRelativePath = "../charts/chart";
break;
}
case DOCUMENT_XLSX:
{
sFullPath = "xl/charts/chart";
sRelativePath = "../charts/chart";
break;
}
default:
{
sFullPath = "charts/chart";
sRelativePath = "charts/chart";
break;
}
}
OUString sFullStream = OUStringBuffer()
.appendAscii(sFullPath)
.append(nChartCount)
.appendAscii( ".xml" )
.makeStringAndClear();
OUString sRelativeStream = OUStringBuffer()
.appendAscii(sRelativePath)
.append(nChartCount)
.appendAscii( ".xml" )
.makeStringAndClear();
FSHelperPtr pChart = CreateOutputStream(
sFullStream,
sRelativeStream,
pFS->getOutputStream(),
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
&sId );
pFS->singleElement( FSNS( XML_c, XML_chart ),
FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart",
FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
FSNS( XML_r, XML_id ), USS( sId ),
FSEND );
pFS->endElement( FSNS( XML_a, XML_graphicData ) );
pFS->endElement( FSNS( XML_a, XML_graphic ) );
pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
SetFS( pChart );
ExportContent();
return *this;
}
void ChartExport::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 ));
OUString sCellRange, sBrokenRange;
bool bBrokenRangeAvailable = false;
for( sal_Int32 i=0; i<aArgs.getLength(); ++i )
{
if ( aArgs[i].Name == "CellRangeRepresentation" )
aArgs[i].Value >>= sCellRange;
else if ( aArgs[i].Name == "BrokenCellRangeForExport" )
{
if( aArgs[i].Value >>= sBrokenRange )
bBrokenRangeAvailable = true;
}
else if ( aArgs[i].Name == "SequenceMapping" )
aArgs[i].Value >>= maSequenceMapping;
}
// #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.isEmpty() )
{
// convert format to XML-conform one
Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY );
if( xConversion.is())
msChartAddress = xConversion->convertRangeToXML( msChartAddress );
}
}
}
catch( const uno::Exception & ex )
{
(void)ex; // avoid warning for pro build
OSL_FAIL( OUStringToOString(
OUString( "Exception caught. Type: " ) +
OUString::createFromAscii( typeid( ex ).name()) +
OUString( ", Message: " ) +
ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
}
}
void ChartExport::ExportContent()
{
Reference< chart2::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
OSL_ASSERT( xChartDoc.is() );
if( !xChartDoc.is() )
return;
InitRangeSegmentationProperties( xChartDoc );
// TODO: export chart
_ExportContent( );
}
void ChartExport::_ExportContent()
{
Reference< ::com::sun::star::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() == "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("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("ChartRangeAddress"));
aAny >>= msChartAddress;
//maExportHelper.SetChartRangeAddress( sChartAddress );
//maExportHelper.SetTableNumberList( sTableNumberList );
// do not include own table if there are external addresses
bIncludeTable = sChartAddress.isEmpty();
}
catch( beans::UnknownPropertyException & )
{
OSL_FAIL( "Property ChartRangeAddress not supported by ChartDocument" );
}
}
}
}
}
exportChartSpace( xChartDoc, bIncludeTable );
}
else
{
OSL_FAIL( "Couldn't export chart due to wrong XModel" );
}
}
void ChartExport::exportChartSpace( Reference< ::com::sun::star::chart::XChartDocument > rChartDoc,
sal_Bool bIncludeTable )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_chartSpace ),
FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart",
FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main",
FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
FSEND );
// TODO: get the correct editing lanauge
pFS->singleElement( FSNS( XML_c, XML_lang ),
XML_val, "en-US",
FSEND );
if( !bIncludeTable )
{
// TODO:external data
}
//XML_chart
exportChart(rChartDoc);
// TODO: printSettings
// TODO: style
// TODO: text properties
// TODO: shape properties
Reference< XPropertySet > xPropSet( rChartDoc->getArea(), uno::UNO_QUERY );
if( xPropSet.is() )
exportShapeProps( xPropSet );
pFS->endElement( FSNS( XML_c, XML_chartSpace ) );
}
void ChartExport::exportChart( Reference< ::com::sun::star::chart::XChartDocument > rChartDoc )
{
Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY );
mxDiagram.set( rChartDoc->getDiagram() );
if( xNewDoc.is())
mxNewDiagram.set( xNewDoc->getFirstDiagram());
// get Properties of ChartDocument
sal_Bool bHasMainTitle = sal_False;
sal_Bool bHasSubTitle = sal_False;
sal_Bool bHasLegend = sal_False;
Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY );
if( xDocPropSet.is())
{
try
{
Any aAny( xDocPropSet->getPropertyValue(
OUString( "HasMainTitle" )));
aAny >>= bHasMainTitle;
aAny = xDocPropSet->getPropertyValue(
OUString( "HasSubTitle" ));
aAny >>= bHasSubTitle;
aAny = xDocPropSet->getPropertyValue(
OUString( "HasLegend" ));
aAny >>= bHasLegend;
}
catch( beans::UnknownPropertyException & )
{
DBG_WARNING( "Required property not found in ChartDocument" );
}
} // if( xDocPropSet.is())
// chart element
// -------------
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_chart ),
FSEND );
// title
if( bHasMainTitle )
{
Reference< drawing::XShape > xShape = rChartDoc->getTitle();
if( xShape.is() )
exportTitle( xShape );
}
InitPlotArea( );
if( mbIs3DChart )
{
exportView3D();
// floor
Reference< beans::XPropertySet > xFloor( mxNewDiagram->getFloor(), uno::UNO_QUERY );
if( xFloor.is() )
{
pFS->startElement( FSNS( XML_c, XML_floor ),
FSEND );
exportShapeProps( xFloor );
pFS->endElement( FSNS( XML_c, XML_floor ) );
}
// sideWall
// backWall
Reference< beans::XPropertySet > xBackWall( mxNewDiagram->getWall(), uno::UNO_QUERY );
if( xBackWall.is() )
{
pFS->startElement( FSNS( XML_c, XML_backWall ),
FSEND );
exportShapeProps( xBackWall );
pFS->endElement( FSNS( XML_c, XML_backWall ) );
}
}
// plot area
exportPlotArea( );
// legend
if( bHasLegend )
exportLegend( rChartDoc );
// only visible cells should be plotted on the chart
pFS->singleElement( FSNS( XML_c, XML_plotVisOnly ),
XML_val, "1",
FSEND );
pFS->endElement( FSNS( XML_c, XML_chart ) );
}
void ChartExport::exportLegend( Reference< ::com::sun::star::chart::XChartDocument > rChartDoc )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_legend ),
FSEND );
Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY );
if( xProp.is() )
{
// position
::com::sun::star::chart::ChartLegendPosition aLegendPos = ::com::sun::star::chart::ChartLegendPosition_NONE;
try
{
Any aAny( xProp->getPropertyValue(
OUString( "Alignment" )));
aAny >>= aLegendPos;
}
catch( beans::UnknownPropertyException & )
{
DBG_WARNING( "Property Align not found in ChartLegend" );
}
const char* strPos = NULL;
switch( aLegendPos )
{
case ::com::sun::star::chart::ChartLegendPosition_LEFT:
strPos = "l";
break;
case ::com::sun::star::chart::ChartLegendPosition_RIGHT:
strPos = "r";
break;
case ::com::sun::star::chart::ChartLegendPosition_TOP:
strPos = "t";
break;
case ::com::sun::star::chart::ChartLegendPosition_BOTTOM:
strPos = "b";
break;
case ::com::sun::star::chart::ChartLegendPosition_NONE:
case ::com::sun::star::chart::ChartLegendPosition_MAKE_FIXED_SIZE:
// nothing
break;
}
if( strPos != NULL )
{
pFS->singleElement( FSNS( XML_c, XML_legendPos ),
XML_val, strPos,
FSEND );
pFS->singleElement( FSNS( XML_c, XML_overlay ),
XML_val, "0",
FSEND );
}
// shape properties
exportShapeProps( xProp );
}
// legendEntry
pFS->endElement( FSNS( XML_c, XML_legend ) );
}
void ChartExport::exportTitle( Reference< XShape > xShape )
{
OUString sText;
Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
if( xPropSet.is())
{
xPropSet->getPropertyValue( OUString( "String" )) >>= sText;
}
if( sText.isEmpty() )
return;
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_title ),
FSEND );
// TODO:customize layout
pFS->singleElement( FSNS( XML_c, XML_layout ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_tx ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_rich ),
FSEND );
// TODO: bodyPr
const char* sWritingMode = NULL;
sal_Bool bVertical = sal_False;
xPropSet->getPropertyValue( OUString( "StackedText" )) >>= bVertical;
if( bVertical )
sWritingMode = "wordArtVert";
pFS->singleElement( FSNS( XML_a, XML_bodyPr ),
XML_vert, sWritingMode,
FSEND );
// TODO: lstStyle
pFS->singleElement( FSNS( XML_a, XML_lstStyle ),
FSEND );
// FIXME: handle multipul paragraphs to parse aText
pFS->startElement( FSNS( XML_a, XML_p ),
FSEND );
pFS->startElement( FSNS( XML_a, XML_pPr ),
FSEND );
pFS->singleElement( FSNS( XML_a, XML_defRPr ),
FSEND );
pFS->endElement( FSNS( XML_a, XML_pPr ) );
pFS->startElement( FSNS( XML_a, XML_r ),
FSEND );
WriteRunProperties( xPropSet, sal_False );
pFS->startElement( FSNS( XML_a, XML_t ),
FSEND );
pFS->writeEscaped( sText );
pFS->endElement( FSNS( XML_a, XML_t ) );
pFS->endElement( FSNS( XML_a, XML_r ) );
pFS->endElement( FSNS( XML_a, XML_p ) );
pFS->endElement( FSNS( XML_c, XML_rich ) );
pFS->endElement( FSNS( XML_c, XML_tx ) );
pFS->endElement( FSNS( XML_c, XML_title ) );
}
void ChartExport::exportPlotArea( )
{
Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( mxNewDiagram, uno::UNO_QUERY );
if( ! xBCooSysCnt.is())
return;
// plot-area element
// -----------------
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_plotArea ),
FSEND );
// layout
pFS->singleElement( FSNS( XML_c, XML_layout ),
FSEND );
// chart type
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())
return;
Reference< chart2::XChartType > xChartType( aCTSeq[nCTIdx], uno::UNO_QUERY );
if( ! xChartType.is())
continue;
// note: if xDSCnt.is() then also aCTSeq[nCTIdx]
OUString aChartType( xChartType->getChartType());
sal_Int32 eChartType = lcl_getChartType( aChartType );
switch( eChartType )
{
case chart::TYPEID_BAR:
{
exportBarChart( xChartType );
break;
}
case chart::TYPEID_AREA:
{
exportAreaChart( xChartType );
break;
}
case chart::TYPEID_LINE:
{
exportLineChart( xChartType );
break;
}
case chart::TYPEID_BUBBLE:
{
exportBubbleChart( xChartType );
break;
}
case chart::TYPEID_DOUGHNUT:
{
exportDoughnutChart( xChartType );
break;
}
case chart::TYPEID_OFPIE:
{
exportOfPieChart( xChartType );
break;
}
case chart::TYPEID_PIE:
{
exportPieChart( xChartType );
break;
}
case chart::TYPEID_RADARLINE:
case chart::TYPEID_RADARAREA:
{
exportRadarChart( xChartType );
break;
}
case chart::TYPEID_SCATTER:
{
exportScatterChart( xChartType );
break;
}
case chart::TYPEID_STOCK:
{
exportStockChart( xChartType );
break;
}
case chart::TYPEID_SURFACE:
{
exportSuffaceChart( xChartType );
break;
}
default:
{
OSL_TRACE("ChartExport::exportPlotArea -- not support chart type");
break;
}
}
}
}
//Axis Data
exportAxes( );
// shape properties
Reference< ::com::sun::star::chart::X3DDisplay > xWallFloorSupplier( mxDiagram, uno::UNO_QUERY );
if( xWallFloorSupplier.is() )
{
Reference< beans::XPropertySet > xWallPropSet( xWallFloorSupplier->getWall(), uno::UNO_QUERY );
if( xWallPropSet.is() )
{
exportShapeProps( xWallPropSet );
}
}
pFS->endElement( FSNS( XML_c, XML_plotArea ) );
}
void ChartExport::exportAreaChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
sal_Int32 nTypeId = XML_areaChart;
if( mbIs3DChart )
nTypeId = XML_area3DChart;
pFS->startElement( FSNS( XML_c, nTypeId ),
FSEND );
exportGrouping( );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, nTypeId ) );
}
void ChartExport::exportBarChart( Reference< chart2::XChartType > xChartType )
{
sal_Int32 nTypeId = XML_barChart;
if( mbIs3DChart )
nTypeId = XML_bar3DChart;
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, nTypeId ),
FSEND );
// bar direction
sal_Bool bVertical = sal_False;
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
if( GetProperty( xPropSet, "Vertical" ) )
mAny >>= bVertical;
const char* bardir = bVertical? "bar":"col";
pFS->singleElement( FSNS( XML_c, XML_barDir ),
XML_val, bardir,
FSEND );
exportGrouping( sal_True );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
Reference< XPropertySet > xTypeProp( xChartType, uno::UNO_QUERY );
if( mbIs3DChart )
{
// Shape
namespace cssc = ::com::sun::star::chart;
sal_Int32 nGeom3d = cssc::ChartSolidType::RECTANGULAR_SOLID;
if( xPropSet.is() && GetProperty( xPropSet, "SolidType") )
mAny >>= nGeom3d;
const char* sShapeType = NULL;
switch( nGeom3d )
{
case cssc::ChartSolidType::RECTANGULAR_SOLID:
sShapeType = "box";
break;
case cssc::ChartSolidType::CONE:
sShapeType = "cone";
break;
case cssc::ChartSolidType::CYLINDER:
sShapeType = "cylinder";
break;
case cssc::ChartSolidType::PYRAMID:
sShapeType = "pyramid";
break;
}
pFS->singleElement( FSNS( XML_c, XML_shape ),
XML_val, sShapeType,
FSEND );
}
//overlap
if( !mbIs3DChart && xTypeProp.is() && GetProperty( xTypeProp, "OverlapSequence") )
{
uno::Sequence< sal_Int32 > aBarPositionSequence;
mAny >>= aBarPositionSequence;
if( aBarPositionSequence.getLength() )
{
sal_Int32 nOverlap = aBarPositionSequence[0];
if( nOverlap > 0 )
pFS->singleElement( FSNS( XML_c, XML_overlap ),
XML_val, I32S( nOverlap ),
FSEND );
}
}
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, nTypeId ) );
}
void ChartExport::exportBubbleChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_bubbleChart ),
FSEND );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, XML_bubbleChart ) );
}
void ChartExport::exportDoughnutChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_doughnutChart ),
FSEND );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
// firstSliceAng
exportFirstSliceAng( );
//FIXME: holeSize
sal_Int32 nHoleSize = 50;
pFS->singleElement( FSNS( XML_c, XML_holeSize ),
XML_val, I32S( nHoleSize ),
FSEND );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, XML_doughnutChart ) );
}
void ChartExport::exportLineChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
sal_Int32 nTypeId = XML_lineChart;
if( mbIs3DChart )
nTypeId = XML_line3DChart;
pFS->startElement( FSNS( XML_c, nTypeId ),
FSEND );
exportGrouping( );
// TODO: show marker symbol in series?
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
// show marker?
sal_Int32 nSymbolType = ::com::sun::star::chart::ChartSymbolType::NONE;
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
if( GetProperty( xPropSet, "SymbolType" ) )
mAny >>= nSymbolType;
const char* marker = nSymbolType == ::com::sun::star::chart::ChartSymbolType::NONE? "0":"1";
pFS->singleElement( FSNS( XML_c, XML_marker ),
XML_val, marker,
FSEND );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, nTypeId ) );
}
void ChartExport::exportOfPieChart( Reference< chart2::XChartType > /*xChartType*/ )
{
// TODO:
}
void ChartExport::exportPieChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
sal_Int32 nTypeId = XML_pieChart;
if( mbIs3DChart )
nTypeId = XML_pie3DChart;
pFS->startElement( FSNS( XML_c, nTypeId ),
FSEND );
// TODO: varyColors
const char* varyColors = "1";
pFS->singleElement( FSNS( XML_c, XML_varyColors ),
XML_val, varyColors,
FSEND );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
// firstSliceAng
exportFirstSliceAng( );
pFS->endElement( FSNS( XML_c, nTypeId ) );
}
void ChartExport::exportRadarChart( Reference< chart2::XChartType > xChartType)
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_radarChart ),
FSEND );
// radarStyle
sal_Int32 eChartType = getChartType( );
const char* radarStyle = NULL;
if( eChartType == chart::TYPEID_RADARAREA )
radarStyle = "filled";
else
radarStyle = "marker";
pFS->singleElement( FSNS( XML_c, XML_radarStyle ),
XML_val, radarStyle,
FSEND );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, XML_radarChart ) );
}
void ChartExport::exportScatterChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_scatterChart ),
FSEND );
// TODO:scatterStyle
const char* scatterStyle = "lineMarker";
pFS->singleElement( FSNS( XML_c, XML_scatterStyle ),
XML_val, scatterStyle,
FSEND );
pFS->singleElement( FSNS( XML_c, XML_varyColors ),
XML_val, "0",
FSEND );
// FIXME: should export xVal and yVal
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, XML_scatterChart ) );
}
void ChartExport::exportStockChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_stockChart ),
FSEND );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
// export stock properties
Reference< ::com::sun::star::chart::XStatisticDisplay > xStockPropProvider( mxDiagram, uno::UNO_QUERY );
if( xStockPropProvider.is())
{
// stock-range-line
Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getMinMaxLine();
if( xStockPropSet.is() )
{
pFS->startElement( FSNS( XML_c, XML_hiLowLines ),
FSEND );
exportShapeProps( xStockPropSet );
pFS->endElement( FSNS( XML_c, XML_hiLowLines ) );
}
// stock updownbar
pFS->startElement( FSNS( XML_c, XML_upDownBars ),
FSEND );
// TODO: gapWidth
sal_Int32 nGapWidth = 150;
pFS->singleElement( FSNS( XML_c, XML_gapWidth ),
XML_val, I32S( nGapWidth ),
FSEND );
xStockPropSet = xStockPropProvider->getUpBar();
if( xStockPropSet.is() )
{
pFS->startElement( FSNS( XML_c, XML_upBars ),
FSEND );
exportShapeProps( xStockPropSet );
pFS->endElement( FSNS( XML_c, XML_upBars ) );
}
xStockPropSet = xStockPropProvider->getDownBar();
if( xStockPropSet.is() )
{
pFS->startElement( FSNS( XML_c, XML_downBars ),
FSEND );
exportShapeProps( xStockPropSet );
pFS->endElement( FSNS( XML_c, XML_downBars ) );
}
pFS->endElement( FSNS( XML_c, XML_upDownBars ) );
}
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, XML_stockChart ) );
}
void ChartExport::exportSuffaceChart( Reference< chart2::XChartType > xChartType )
{
FSHelperPtr pFS = GetFS();
sal_Int32 nTypeId = XML_surfaceChart;
if( mbIs3DChart )
nTypeId = XML_surface3DChart;
pFS->startElement( FSNS( XML_c, nTypeId ),
FSEND );
sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
exportSeries( xChartType, nAttachedAxis );
exportAxesId( nAttachedAxis );
pFS->endElement( FSNS( XML_c, nTypeId ) );
}
void ChartExport::exportSeries( Reference< chart2::XChartType > xChartType, sal_Int32& nAttachedAxis )
{
OUString aLabelRole = xChartType->getRoleOfSequenceForSeriesLabel();
Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
if( ! xDSCnt.is())
return;
OUString aChartType( xChartType->getChartType());
sal_Int32 eChartType = lcl_getChartType( aChartType );
// special export for stock charts
if( eChartType == chart::TYPEID_STOCK )
{
sal_Bool bJapaneseCandleSticks = sal_False;
Reference< beans::XPropertySet > xCTProp( xChartType, uno::UNO_QUERY );
if( xCTProp.is())
xCTProp->getPropertyValue( OUString("Japanese")) >>= bJapaneseCandleSticks;
exportCandleStickSeries(
xDSCnt->getDataSeries(), bJapaneseCandleSticks, nAttachedAxis );
return;
}
// 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())
{
Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
xSource->getDataSequences());
// search for main sequence and create a series element
{
sal_Int32 nMainSequenceIndex = -1;
sal_Int32 nSeriesLength = 0;
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("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
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_ser ),
FSEND );
// TODO: idx and order
pFS->singleElement( FSNS( XML_c, XML_idx ),
XML_val, I32S(nSeriesIdx),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_order ),
XML_val, I32S(nSeriesIdx),
FSEND );
// export label
if( xLabelSeq.is() )
exportSeriesText( xLabelSeq );
// export shape properties
Reference< XPropertySet > xPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet(
aSeriesSeq[nSeriesIdx], getModel() );
if( xPropSet.is() )
{
if( GetProperty( xPropSet, "Axis") )
{
mAny >>= nAttachedAxis;
if( nAttachedAxis == ::com::sun::star::chart::ChartAxisAssign::SECONDARY_Y )
nAttachedAxis = AXIS_SECONDARY_Y;
else
nAttachedAxis = AXIS_PRIMARY_Y;
}
exportShapeProps( xPropSet );
}
switch( eChartType )
{
case chart::TYPEID_LINE:
{
exportMarker( );
break;
}
case chart::TYPEID_PIE:
case chart::TYPEID_DOUGHNUT:
{
if( xPropSet.is() && GetProperty( xPropSet, "SegmentOffset") )
{
sal_Int32 nOffset = 0;
mAny >>= nOffset;
pFS->singleElement( FSNS( XML_c, XML_explosion ),
XML_val, I32S( nOffset ),
FSEND );
}
break;
}
case chart::TYPEID_SCATTER:
{
exportMarker( );
exportSmooth( );
break;
}
case chart::TYPEID_RADARLINE:
{
exportMarker( );
break;
}
}
// export data labels
// Excel does not like our current data label export
// for scatter charts
if( eChartType != chart::TYPEID_SCATTER )
exportDataLabels( uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ), nSeriesLength );
// export data points
exportDataPoints( uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ), nSeriesLength );
//export error bars here
Reference< XPropertySet > xSeriesPropSet( xSource, uno::UNO_QUERY );
Reference< XPropertySet > xErrorBarYProps;
xSeriesPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarYProps;
if(xErrorBarYProps.is())
exportErrorBar(xErrorBarYProps, true);
Reference< XPropertySet > xErrorBarXProps;
xSeriesPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarXProps;
if(xErrorBarXProps.is())
exportErrorBar(xErrorBarXProps, false);
// export categories
if( mxCategoriesValues.is() )
exportSeriesCategory( mxCategoriesValues );
if( (eChartType == chart::TYPEID_SCATTER)
|| (eChartType == chart::TYPEID_BUBBLE) )
{
// export xVal
Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, OUString("values-x") ) );
if( xSequence.is() )
{
Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
if( xValues.is() )
exportSeriesValues( xValues, XML_xVal );
}
}
if( eChartType == chart::TYPEID_BUBBLE )
{
// export yVal
Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, OUString("values-y") ) );
if( xSequence.is() )
{
Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
if( xValues.is() )
exportSeriesValues( xValues, XML_yVal );
}
}
// export values
if( xValuesSeq.is() )
{
sal_Int32 nYValueType = XML_val;
if( eChartType == chart::TYPEID_SCATTER )
nYValueType = XML_yVal;
else if( eChartType == chart::TYPEID_BUBBLE )
nYValueType = XML_bubbleSize;
exportSeriesValues( xValuesSeq, nYValueType );
}
pFS->endElement( FSNS( XML_c, XML_ser ) );
}
}
}
}
}
void ChartExport::exportCandleStickSeries(
const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
sal_Bool /*bJapaneseCandleSticks*/,
sal_Int32& nAttachedAxis )
{
for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx )
{
Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nSeriesIdx] );
nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries ) ? AXIS_PRIMARY_Y : AXIS_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());
Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
const char* sSeries[] = {"values-first","values-max","values-min","values-last",0};
for( sal_Int32 idx = 0; sSeries[idx] != 0 ; idx++ )
{
Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii(sSeries[idx]) ) );
if( xLabeledSeq.is())
{
Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_ser ),
FSEND );
// TODO: idx and order
pFS->singleElement( FSNS( XML_c, XML_idx ),
XML_val, I32S(idx),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_order ),
XML_val, I32S(idx),
FSEND );
// export label
if( xLabelSeq.is() )
exportSeriesText( xLabelSeq );
// TODO:export shape properties
// export categories
if( mxCategoriesValues.is() )
exportSeriesCategory( mxCategoriesValues );
// export values
if( xValueSeq.is() )
exportSeriesValues( xValueSeq );
pFS->endElement( FSNS( XML_c, XML_ser ) );
}
}
}
}
}
}
void ChartExport::exportSeriesText( const Reference< chart2::data::XDataSequence > & xValueSeq )
{
FSHelperPtr pFS = GetFS();
Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
pFS->startElement( FSNS( XML_c, XML_tx ),
FSEND );
OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
aCellRange = parseFormula( aCellRange );
pFS->startElement( FSNS( XML_c, XML_strRef ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_f ),
FSEND );
pFS->writeEscaped( aCellRange );
pFS->endElement( FSNS( XML_c, XML_f ) );
OUString aLabelString = lcl_getLabelString( xValueSeq );
pFS->startElement( FSNS( XML_c, XML_strCache ),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_ptCount ),
XML_val, "1",
FSEND );
pFS->startElement( FSNS( XML_c, XML_pt ),
XML_idx, "0",
FSEND );
pFS->startElement( FSNS( XML_c, XML_v ),
FSEND );
pFS->writeEscaped( aLabelString );
pFS->endElement( FSNS( XML_c, XML_v ) );
pFS->endElement( FSNS( XML_c, XML_pt ) );
pFS->endElement( FSNS( XML_c, XML_strCache ) );
pFS->endElement( FSNS( XML_c, XML_strRef ) );
pFS->endElement( FSNS( XML_c, XML_tx ) );
}
void ChartExport::exportSeriesCategory( const Reference< chart2::data::XDataSequence > & xValueSeq )
{
FSHelperPtr pFS = GetFS();
Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
pFS->startElement( FSNS( XML_c, XML_cat ),
FSEND );
OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
aCellRange = parseFormula( aCellRange );
// TODO: need to handle XML_multiLvlStrRef according to aCellRange
pFS->startElement( FSNS( XML_c, XML_strRef ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_f ),
FSEND );
pFS->writeEscaped( aCellRange );
pFS->endElement( FSNS( XML_c, XML_f ) );
::std::vector< OUString > aCategories;
lcl_fillCategoriesIntoStringVector( xValueSeq, aCategories );
sal_Int32 ptCount = aCategories.size();
pFS->startElement( FSNS( XML_c, XML_strCache ),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_ptCount ),
XML_val, I32S( ptCount ),
FSEND );
for( sal_Int32 i = 0; i < ptCount; i++ )
{
pFS->startElement( FSNS( XML_c, XML_pt ),
XML_idx, I32S( i ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_v ),
FSEND );
pFS->writeEscaped( aCategories[i] );
pFS->endElement( FSNS( XML_c, XML_v ) );
pFS->endElement( FSNS( XML_c, XML_pt ) );
}
pFS->endElement( FSNS( XML_c, XML_strCache ) );
pFS->endElement( FSNS( XML_c, XML_strRef ) );
pFS->endElement( FSNS( XML_c, XML_cat ) );
}
void ChartExport::exportSeriesValues( const Reference< chart2::data::XDataSequence > & xValueSeq, sal_Int32 nValueType )
{
FSHelperPtr pFS = GetFS();
Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
pFS->startElement( FSNS( XML_c, nValueType ),
FSEND );
OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
aCellRange = parseFormula( aCellRange );
// TODO: need to handle XML_multiLvlStrRef according to aCellRange
pFS->startElement( FSNS( XML_c, XML_numRef ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_f ),
FSEND );
pFS->writeEscaped( aCellRange );
pFS->endElement( FSNS( XML_c, XML_f ) );
::std::vector< double > aValues;
aValues = lcl_getAllValuesFromSequence( xValueSeq );
sal_Int32 ptCount = aValues.size();
pFS->startElement( FSNS( XML_c, XML_numCache ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_formatCode ),
FSEND );
// TODO: what format code?
pFS->writeEscaped( "General" );
pFS->endElement( FSNS( XML_c, XML_formatCode ) );
pFS->singleElement( FSNS( XML_c, XML_ptCount ),
XML_val, I32S( ptCount ),
FSEND );
for( sal_Int32 i = 0; i < ptCount; i++ )
{
pFS->startElement( FSNS( XML_c, XML_pt ),
XML_idx, I32S( i ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_v ),
FSEND );
if (aValues[i] == aValues[i])
pFS->write( aValues[i] );
pFS->endElement( FSNS( XML_c, XML_v ) );
pFS->endElement( FSNS( XML_c, XML_pt ) );
}
pFS->endElement( FSNS( XML_c, XML_numCache ) );
pFS->endElement( FSNS( XML_c, XML_numRef ) );
pFS->endElement( FSNS( XML_c, nValueType ) );
}
void ChartExport::exportShapeProps( Reference< XPropertySet > xPropSet )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_spPr ),
FSEND );
WriteFill( xPropSet );
WriteOutline( xPropSet );
pFS->endElement( FSNS( XML_c, XML_spPr ) );
}
void ChartExport::InitPlotArea( )
{
Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
// Check for supported services and then the properties provided by this service.
Reference<lang::XServiceInfo> xServiceInfo (mxDiagram, uno::UNO_QUERY);
if (xServiceInfo.is())
{
if (xServiceInfo->supportsService(
OUString("com.sun.star.chart.ChartAxisZSupplier")))
{
xDiagramProperties->getPropertyValue(
OUString("HasZAxis")) >>= mbHasZAxis;
}
}
xDiagramProperties->getPropertyValue(
OUString ("Dim3D")) >>= mbIs3DChart;
Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
if( mbHasCategoryLabels && mxNewDiagram.is())
{
Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( mxNewDiagram ) );
if( xCategories.is() )
{
mxCategoriesValues.set( xCategories->getValues() );
}
}
}
void ChartExport::exportAxes( )
{
sal_Int32 nSize = maAxes.size();
for( sal_Int32 nIdx = 0; nIdx < nSize; nIdx++ )
{
exportAxis( maAxes[nIdx] );
}
}
void ChartExport::exportAxis( AxisIdPair aAxisIdPair )
{
// get some properties from document first
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;
Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
xDiagramProperties->getPropertyValue(
OUString ("HasXAxisTitle")) >>= bHasXAxisTitle;
xDiagramProperties->getPropertyValue(
OUString ("HasYAxisTitle")) >>= bHasYAxisTitle;
xDiagramProperties->getPropertyValue(
OUString ("HasZAxisTitle")) >>= bHasZAxisTitle;
xDiagramProperties->getPropertyValue(
OUString ("HasSecondaryXAxisTitle")) >>= bHasSecondaryXAxisTitle;
xDiagramProperties->getPropertyValue(
OUString ("HasSecondaryYAxisTitle")) >>= bHasSecondaryYAxisTitle;
xDiagramProperties->getPropertyValue(
OUString ("HasXAxisGrid")) >>= bHasXAxisMajorGrid;
xDiagramProperties->getPropertyValue(
OUString ("HasYAxisGrid")) >>= bHasYAxisMajorGrid;
xDiagramProperties->getPropertyValue(
OUString ("HasZAxisGrid")) >>= bHasZAxisMajorGrid;
xDiagramProperties->getPropertyValue(
OUString ("HasXAxisHelpGrid")) >>= bHasXAxisMinorGrid;
xDiagramProperties->getPropertyValue(
OUString ("HasYAxisHelpGrid")) >>= bHasYAxisMinorGrid;
xDiagramProperties->getPropertyValue(
OUString ("HasZAxisHelpGrid")) >>= bHasZAxisMinorGrid;
Reference< XPropertySet > xAxisProp;
Reference< drawing::XShape > xAxisTitle;
Reference< beans::XPropertySet > xMajorGrid;
Reference< beans::XPropertySet > xMinorGrid;
sal_Int32 nAxisType = XML_catAx;
const char* sAxPos = NULL;
switch( aAxisIdPair.nAxisType )
{
case AXIS_PRIMARY_X:
{
Reference< ::com::sun::star::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
if( xAxisXSupp.is())
xAxisProp = xAxisXSupp->getXAxis();
if( bHasXAxisTitle )
xAxisTitle.set( xAxisXSupp->getXAxisTitle(), uno::UNO_QUERY );
if( bHasXAxisMajorGrid )
xMajorGrid.set( xAxisXSupp->getXMainGrid(), uno::UNO_QUERY );
if( bHasXAxisMinorGrid )
xMinorGrid.set( xAxisXSupp->getXHelpGrid(), uno::UNO_QUERY );
sal_Int32 eChartType = getChartType( );
if( (eChartType == chart::TYPEID_SCATTER)
|| (eChartType == chart::TYPEID_BUBBLE) )
nAxisType = XML_valAx;
else if( eChartType == chart::TYPEID_STOCK )
nAxisType = XML_dateAx;
// FIXME: axPos, need to check axis direction
sAxPos = "b";
break;
}
case AXIS_PRIMARY_Y:
{
Reference< ::com::sun::star::chart::XAxisYSupplier > xAxisYSupp( mxDiagram, uno::UNO_QUERY );
if( xAxisYSupp.is())
xAxisProp = xAxisYSupp->getYAxis();
if( bHasYAxisTitle )
xAxisTitle.set( xAxisYSupp->getYAxisTitle(), uno::UNO_QUERY );
if( bHasYAxisMajorGrid )
xMajorGrid.set( xAxisYSupp->getYMainGrid(), uno::UNO_QUERY );
if( bHasYAxisMinorGrid )
xMinorGrid.set( xAxisYSupp->getYHelpGrid(), uno::UNO_QUERY );
nAxisType = XML_valAx;
// FIXME: axPos, need to check axis direction
sAxPos = "l";
break;
}
case AXIS_PRIMARY_Z:
{
Reference< ::com::sun::star::chart::XAxisZSupplier > xAxisZSupp( mxDiagram, uno::UNO_QUERY );
if( xAxisZSupp.is())
xAxisProp = xAxisZSupp->getZAxis();
if( bHasZAxisTitle )
xAxisTitle.set( xAxisZSupp->getZAxisTitle(), uno::UNO_QUERY );
if( bHasZAxisMajorGrid )
xMajorGrid.set( xAxisZSupp->getZMainGrid(), uno::UNO_QUERY );
if( bHasZAxisMinorGrid )
xMinorGrid.set( xAxisZSupp->getZHelpGrid(), uno::UNO_QUERY );
sal_Int32 eChartType = getChartType( );
if( (eChartType == chart::TYPEID_SCATTER)
|| (eChartType == chart::TYPEID_BUBBLE) )
nAxisType = XML_valAx;
else if( eChartType == chart::TYPEID_STOCK )
nAxisType = XML_dateAx;
// FIXME: axPos, need to check axis direction
sAxPos = "b";
break;
}
case AXIS_SECONDARY_Y:
{
Reference< ::com::sun::star::chart::XTwoAxisYSupplier > xAxisTwoYSupp( mxDiagram, uno::UNO_QUERY );
if( xAxisTwoYSupp.is())
xAxisProp = xAxisTwoYSupp->getSecondaryYAxis();
if( bHasSecondaryYAxisTitle )
{
Reference< ::com::sun::star::chart::XSecondAxisTitleSupplier > xAxisSupp( mxDiagram, uno::UNO_QUERY );
xAxisTitle.set( xAxisSupp->getSecondYAxisTitle(), uno::UNO_QUERY );
}
nAxisType = XML_valAx;
// FIXME: axPos, need to check axis direction
sAxPos = "l";
break;
}
}
_exportAxis( xAxisProp, xAxisTitle, xMajorGrid, xMinorGrid, nAxisType, sAxPos, aAxisIdPair );
}
void ChartExport::_exportAxis(
const Reference< XPropertySet >& xAxisProp,
const Reference< drawing::XShape >& xAxisTitle,
const Reference< XPropertySet >& xMajorGrid,
const Reference< XPropertySet >& xMinorGrid,
sal_Int32 nAxisType,
const char* sAxisPos,
AxisIdPair aAxisIdPair )
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, nAxisType ),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_axId ),
XML_val, I32S( aAxisIdPair.nAxisId ),
FSEND );
pFS->startElement( FSNS( XML_c, XML_scaling ),
FSEND );
// orientation: minMax, maxMin
sal_Bool bReverseDirection = sal_False;
if(GetProperty( xAxisProp, "ReverseDirection" ) )
mAny >>= bReverseDirection;
const char* orientation = bReverseDirection ? "maxMin":"minMax";
pFS->singleElement( FSNS( XML_c, XML_orientation ),
XML_val, orientation,
FSEND );
// logBase, min, max
if(GetProperty( xAxisProp, "Logarithmic" ) )
{
sal_Bool bLogarithmic = sal_False;
mAny >>= bLogarithmic;
if( bLogarithmic )
{
// default value is 10?
sal_Int32 nLogBase = 10;
pFS->singleElement( FSNS( XML_c, XML_logBase ),
XML_val, I32S( nLogBase ),
FSEND );
}
}
sal_Bool bAutoMax = sal_False;
if(GetProperty( xAxisProp, "AutoMax" ) )
mAny >>= bAutoMax;
if( !bAutoMax && (GetProperty( xAxisProp, "Max" ) ) )
{
double dMax = 0;
mAny >>= dMax;
pFS->singleElement( FSNS( XML_c, XML_max ),
XML_val, IS( dMax ),
FSEND );
}
sal_Bool bAutoMin = sal_False;
if(GetProperty( xAxisProp, "AutoMin" ) )
mAny >>= bAutoMin;
if( !bAutoMin && (GetProperty( xAxisProp, "Min" ) ) )
{
double dMin = 0;
mAny >>= dMin;
pFS->singleElement( FSNS( XML_c, XML_min ),
XML_val, IS( dMin ),
FSEND );
}
pFS->endElement( FSNS( XML_c, XML_scaling ) );
// title
if( xAxisTitle.is() )
exportTitle( xAxisTitle );
sal_Bool bVisible = sal_True;
if( xAxisProp.is() )
{
xAxisProp->getPropertyValue(
OUString ("Visible")) >>= bVisible;
}
pFS->singleElement( FSNS( XML_c, XML_delete ),
XML_val, bVisible ? "0" : "1",
FSEND );
// FIXME: axPos, need to check the property "ReverseDirection"
pFS->singleElement( FSNS( XML_c, XML_axPos ),
XML_val, sAxisPos,
FSEND );
// major grid line
if( xMajorGrid.is())
{
pFS->startElement( FSNS( XML_c, XML_majorGridlines ),
FSEND );
exportShapeProps( xMajorGrid );
pFS->endElement( FSNS( XML_c, XML_majorGridlines ) );
}
// minor grid line
if( xMinorGrid.is())
{
pFS->startElement( FSNS( XML_c, XML_minorGridlines ),
FSEND );
exportShapeProps( xMajorGrid );
pFS->endElement( FSNS( XML_c, XML_minorGridlines ) );
}
// majorTickMark
sal_Int32 nValue = 0;
if(GetProperty( xAxisProp, "Marks" ) )
{
mAny >>= nValue;
sal_Bool bInner = nValue & ::com::sun::star::chart::ChartAxisMarks::INNER;
sal_Bool bOuter = nValue & ::com::sun::star::chart::ChartAxisMarks::OUTER;
const char* majorTickMark = NULL;
if( bInner && bOuter )
majorTickMark = "cross";
else if( bInner )
majorTickMark = "in";
else if( bOuter )
majorTickMark = "out";
else
majorTickMark = "none";
pFS->singleElement( FSNS( XML_c, XML_majorTickMark ),
XML_val, majorTickMark,
FSEND );
}
// minorTickMark
if(GetProperty( xAxisProp, "HelpMarks" ) )
{
mAny >>= nValue;
sal_Bool bInner = nValue & ::com::sun::star::chart::ChartAxisMarks::INNER;
sal_Bool bOuter = nValue & ::com::sun::star::chart::ChartAxisMarks::OUTER;
const char* minorTickMark = NULL;
if( bInner && bOuter )
minorTickMark = "cross";
else if( bInner )
minorTickMark = "in";
else if( bOuter )
minorTickMark = "out";
else
minorTickMark = "none";
pFS->singleElement( FSNS( XML_c, XML_minorTickMark ),
XML_val, minorTickMark,
FSEND );
}
// tickLblPos
const char* sTickLblPos = NULL;
sal_Bool bDisplayLabel = sal_True;
if(GetProperty( xAxisProp, "DisplayLabels" ) )
mAny >>= bDisplayLabel;
if( bDisplayLabel && (GetProperty( xAxisProp, "LabelPosition" ) ) )
{
::com::sun::star::chart::ChartAxisLabelPosition eLabelPosition = ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS;
mAny >>= eLabelPosition;
switch( eLabelPosition )
{
case ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS:
case ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE:
sTickLblPos = "nextTo";
break;
case ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START:
sTickLblPos = "low";
break;
case ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END:
sTickLblPos = "high";
break;
default:
sTickLblPos = "nextTo";
break;
}
}
else
{
sTickLblPos = "none";
}
pFS->singleElement( FSNS( XML_c, XML_tickLblPos ),
XML_val, sTickLblPos,
FSEND );
// shape properties
exportShapeProps( xAxisProp );
pFS->singleElement( FSNS( XML_c, XML_crossAx ),
XML_val, I32S( aAxisIdPair.nCrossAx ),
FSEND );
// crosses & crossesAt
sal_Bool bCrossesValue = sal_False;
const char* sCrosses = NULL;
if(GetProperty( xAxisProp, "CrossoverPosition" ) )
{
::com::sun::star::chart::ChartAxisPosition ePosition( ::com::sun::star::chart::ChartAxisPosition_ZERO );
mAny >>= ePosition;
switch( ePosition )
{
case ::com::sun::star::chart::ChartAxisPosition_START:
sCrosses = "min";
break;
case ::com::sun::star::chart::ChartAxisPosition_END:
sCrosses = "max";
break;
case ::com::sun::star::chart::ChartAxisPosition_ZERO:
sCrosses = "autoZero";
break;
default:
bCrossesValue = sal_True;
break;
}
}
if( bCrossesValue && GetProperty( xAxisProp, "CrossoverValue" ) )
{
double dValue = 0;
mAny >>= dValue;
pFS->singleElement( FSNS( XML_c, XML_crossesAt ),
XML_val, IS( dValue ),
FSEND );
}
else
{
pFS->singleElement( FSNS( XML_c, XML_crosses ),
XML_val, sCrosses,
FSEND );
}
if( nAxisType == XML_catAx )
{
// FIXME: seems not support? lblAlgn
const char* sLblAlgn = "ctr";
pFS->singleElement( FSNS( XML_c, XML_lblAlgn ),
XML_val, sLblAlgn,
FSEND );
}
if( ( nAxisType == XML_catAx )
|| ( nAxisType == XML_dateAx ) )
{
// FIXME: seems not support? use default value,
const char* isAuto = "1";
pFS->singleElement( FSNS( XML_c, XML_auto ),
XML_val, isAuto,
FSEND );
// FIXME: seems not support? lblOffset
sal_Int32 nLblOffset = 100;
pFS->singleElement( FSNS( XML_c, XML_lblOffset ),
XML_val, I32S( nLblOffset ),
FSEND );
}
// majorUnit
sal_Bool bAutoStepMain = sal_False;
if(GetProperty( xAxisProp, "AutoStepMain" ) )
mAny >>= bAutoStepMain;
if( !bAutoStepMain && (GetProperty( xAxisProp, "StepMain" ) ) )
{
double dMajorUnit = 0;
mAny >>= dMajorUnit;
pFS->singleElement( FSNS( XML_c, XML_majorUnit ),
XML_val, IS( dMajorUnit ),
FSEND );
}
// minorUnit
sal_Bool bAutoStepHelp = sal_False;
if(GetProperty( xAxisProp, "AutoStepHelp" ) )
mAny >>= bAutoStepHelp;
if( !bAutoStepHelp && (GetProperty( xAxisProp, "StepHelp" ) ) )
{
double dMinorUnit = 0;
mAny >>= dMinorUnit;
pFS->singleElement( FSNS( XML_c, XML_minorUnit ),
XML_val, IS( dMinorUnit ),
FSEND );
}
// TODO: text properties
pFS->endElement( FSNS( XML_c, nAxisType ) );
}
void ChartExport::exportDataLabels(
const uno::Reference< beans::XPropertySet > & xSeriesProperties,
sal_Int32 nSeriesLength )
{
// TODO: export field separators, missing flag vs. showing series name or not
uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
if( xSeriesProperties.is())
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_dLbls ),
FSEND );
sal_Int32 nElem;
for( nElem = 0; nElem < nSeriesLength; ++nElem)
{
uno::Reference< beans::XPropertySet > xPropSet;
try
{
xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
xSeries, nElem, getModel() );
}
catch( const uno::Exception & rEx )
{
SAL_WARN("oox", "Exception caught during Export of data label: " << rEx.Message );
}
if( xPropSet.is() )
{
namespace cssc2 = ::com::sun::star::chart2;
cssc2::DataPointLabel aLabel;
if (GetProperty( xPropSet, "Label"))
{
mAny >>= aLabel;
namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
sal_Int32 nPlacement(csscd::AVOID_OVERLAP);
const char *aPlacement = NULL;
OUString aSep;
if (GetProperty( xPropSet, "LabelPlacement"))
mAny >>= nPlacement;
switch( nPlacement )
{
case csscd::OUTSIDE: aPlacement = "outEnd"; break;
case csscd::INSIDE: aPlacement = "inEnd"; break;
case csscd::CENTER: aPlacement = "ctr"; break;
case csscd::NEAR_ORIGIN: aPlacement = "inBase"; break;
case csscd::TOP: aPlacement = "t"; break;
case csscd::BOTTOM: aPlacement = "b"; break;
case csscd::LEFT: aPlacement = "l"; break;
case csscd::RIGHT: aPlacement = "r"; break;
case csscd::AVOID_OVERLAP: aPlacement = "bestFit"; break;
}
pFS->startElement( FSNS( XML_c, XML_dLbl ), FSEND);
pFS->singleElement( FSNS( XML_c, XML_idx), XML_val, I32S(nElem), FSEND);
pFS->singleElement( FSNS( XML_c, XML_dLblPos), XML_val, aPlacement, FSEND);
pFS->singleElement( FSNS( XML_c, XML_showLegendKey), XML_val,
aLabel.ShowLegendSymbol ? "1" : "0", FSEND);
pFS->singleElement( FSNS( XML_c, XML_showVal), XML_val,
aLabel.ShowNumber ? "1" : "0", FSEND);
pFS->singleElement( FSNS( XML_c, XML_showCatName), XML_val,
aLabel.ShowCategoryName ? "1" : "0", FSEND);
// MSO somehow assumes series name to be on (=displayed) by default.
// Let's put false here and switch it off then, since we have no UI means
// in LibO to toggle it on anyway
pFS->singleElement( FSNS( XML_c, XML_showSerName), XML_val, "0", FSEND);
pFS->singleElement( FSNS( XML_c, XML_showPercent), XML_val,
aLabel.ShowNumberInPercent ? "1" : "0", FSEND);
if (GetProperty( xPropSet, "LabelSeparator"))
{
mAny >>= aSep;
pFS->startElement( FSNS( XML_c, XML_separator), FSEND);
pFS->writeEscaped(aSep);
pFS->endElement( FSNS( XML_c, XML_separator) );
}
pFS->endElement( FSNS( XML_c, XML_dLbl ));
}
}
}
pFS->endElement( FSNS( XML_c, XML_dLbls ) );
}
}
void ChartExport::exportDataPoints(
const uno::Reference< beans::XPropertySet > & xSeriesProperties,
sal_Int32 nSeriesLength )
{
uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
bool bVaryColorsByPoint = false;
Sequence< sal_Int32 > aDataPointSeq;
if( xSeriesProperties.is())
{
Any aAny = xSeriesProperties->getPropertyValue(
OUString( "AttributedDataPoints" ));
aAny >>= aDataPointSeq;
xSeriesProperties->getPropertyValue(
OUString( "VaryColorsByPoint" )) >>= bVaryColorsByPoint;
}
const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
sal_Int32 nElement;
Reference< chart2::XColorScheme > xColorScheme;
if( mxNewDiagram.is())
xColorScheme.set( mxNewDiagram->getDefaultColorScheme());
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 )
{
uno::Reference< beans::XPropertySet > xPropSet;
if( aAttrPointSet.find( nElement ) != aEndIt )
{
try
{
xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
xSeries, nElement, getModel() );
}
catch( const uno::Exception & rEx )
{
(void)rEx; // avoid warning for pro build
SAL_WARN( "oox", "Exception caught during Export of data point: " << rEx.Message );
}
}
else
{
// property set only containing the color
xPropSet.set( new ColorPropertySet( xColorScheme->getColorByIndex( nElement )));
}
if( xPropSet.is() )
{
OSL_TRACE("ChartExport::exportDataPoints -- writer data points ");
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_dPt ),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_idx ),
XML_val, I32S(nElement),
FSEND );
exportShapeProps( xPropSet );
pFS->endElement( FSNS( XML_c, XML_dPt ) );
}
}
}
}
void ChartExport::exportAxesId( sal_Int32 nAttachedAxis )
{
sal_Int32 nAxisIdx = lcl_generateRandomValue();
sal_Int32 nAxisIdy = lcl_generateRandomValue();
maAxes.push_back( AxisIdPair( AXIS_PRIMARY_X, nAxisIdx, nAxisIdy ) );
maAxes.push_back( AxisIdPair( nAttachedAxis, nAxisIdy, nAxisIdx ) );
FSHelperPtr pFS = GetFS();
pFS->singleElement( FSNS( XML_c, XML_axId ),
XML_val, I32S( nAxisIdx ),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_axId ),
XML_val, I32S( nAxisIdy ),
FSEND );
if( mbHasZAxis )
{
sal_Int32 nAxisIdz = 0;
if( isDeep3dChart() )
{
nAxisIdz = lcl_generateRandomValue();
maAxes.push_back( AxisIdPair( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy ) );
}
pFS->singleElement( FSNS( XML_c, XML_axId ),
XML_val, I32S( nAxisIdz ),
FSEND );
}
}
void ChartExport::exportGrouping( sal_Bool isBar )
{
FSHelperPtr pFS = GetFS();
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
// grouping
sal_Bool bStacked = sal_False;
if( GetProperty( xPropSet, "Stacked" ) )
mAny >>= bStacked;
sal_Bool bPercentage = sal_False;
if( GetProperty( xPropSet, "Percent" ) )
mAny >>= bPercentage;
const char* grouping = NULL;
if( bStacked )
grouping = "stacked";
else if( bPercentage )
grouping = "percentStacked";
else
{
if( isBar && !isDeep3dChart() )
grouping = "clustered";
else
grouping = "standard";
}
pFS->singleElement( FSNS( XML_c, XML_grouping ),
XML_val, grouping,
FSEND );
}
void ChartExport::exportMarker()
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_marker ),
FSEND );
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY );
sal_Int32 nSymbolType = ::com::sun::star::chart::ChartSymbolType::NONE;
if( GetProperty( xPropSet, "SymbolType" ) )
mAny >>= nSymbolType;
// TODO: more properties support for marker
const char* pSymbolType = NULL;
switch( nSymbolType )
{
case cssc::ChartSymbolType::NONE:
pSymbolType = "none";
break;
case cssc::ChartSymbolType::SYMBOL0:
pSymbolType = "square";
break;
case cssc::ChartSymbolType::SYMBOL1:
pSymbolType = "diamond";
break;
// map all triangle variants to the OOXML version
case cssc::ChartSymbolType::SYMBOL2:
case cssc::ChartSymbolType::SYMBOL3:
case cssc::ChartSymbolType::SYMBOL4:
case cssc::ChartSymbolType::SYMBOL5:
pSymbolType = "triangle";
break;
case cssc::ChartSymbolType::SYMBOL6:
pSymbolType = "plus";
break;
case cssc::ChartSymbolType::SYMBOL7:
pSymbolType = "plus";
break;
case cssc::ChartSymbolType::AUTO:
break;
case cssc::ChartSymbolType::BITMAPURL:
break;
default:
SAL_WARN("oox", "unknown data series symbol");
}
if( pSymbolType )
{
pFS->singleElement( FSNS( XML_c, XML_symbol ),
XML_val, pSymbolType,
FSEND );
}
if( nSymbolType != cssc::ChartSymbolType::NONE )
{
awt::Size aSymbolSize;
if( GetProperty( xPropSet, "SymbolSize" ) )
{
mAny >>= aSymbolSize;;
sal_Int32 nSize = std::max( aSymbolSize.Width, aSymbolSize.Height );
nSize = nSize/250.0*7.0; // just guessed based on some test cases
nSize = std::min<sal_Int32>( 72, std::max<sal_Int32>( 2, nSize ) );
pFS->singleElement( FSNS( XML_c, XML_size),
XML_val, I32S(nSize),
FSEND );
}
}
pFS->endElement( FSNS( XML_c, XML_marker ) );
}
void ChartExport::exportSmooth()
{
FSHelperPtr pFS = GetFS();
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY );
sal_Int32 nSplineType = 0;
if( GetProperty( xPropSet, "SplineType" ) )
mAny >>= nSplineType;
if( nSplineType != 0 )
{
pFS->singleElement( FSNS( XML_c, XML_smooth ),
XML_val, "1",
FSEND );
}
}
void ChartExport::exportFirstSliceAng( )
{
FSHelperPtr pFS = GetFS();
sal_Int32 nStartingAngle = 0;
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
if( GetProperty( xPropSet, "StartingAngle" ) )
mAny >>= nStartingAngle;
// convert to ooxml angle
nStartingAngle = (450 - nStartingAngle ) % 360;
pFS->singleElement( FSNS( XML_c, XML_firstSliceAng ),
XML_val, I32S( nStartingAngle ),
FSEND );
}
namespace {
const char* getErrorBarStyle(sal_Int32 nErrorBarStyle)
{
switch(nErrorBarStyle)
{
case cssc::ErrorBarStyle::NONE:
// I have no idea how to map it to OOXML
// this approach is as good as any else
return "fixedVal";
case cssc::ErrorBarStyle::VARIANCE:
break;
case cssc::ErrorBarStyle::STANDARD_DEVIATION:
return "stdDev";
case cssc::ErrorBarStyle::ABSOLUTE:
return "fixedVal";
case cssc::ErrorBarStyle::RELATIVE:
return "percentage";
case cssc::ErrorBarStyle::ERROR_MARGIN:
break;
case cssc::ErrorBarStyle::STANDARD_ERROR:
return "stdErr";
case cssc::ErrorBarStyle::FROM_DATA:
return "cust";
default:
assert(false); // can't happen
}
return "";
}
Reference< chart2::data::XDataSequence> getLabeledSequence(
uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences,
bool bPositive )
{
const OUString aRolePrefix( "error-bars" );
OUString aDirection;
if(bPositive)
aDirection = "positive";
else
aDirection = "negative";
for( sal_Int32 nI=0; nI< aSequences.getLength(); ++nI )
{
if( aSequences[nI].is())
{
uno::Reference< chart2::data::XDataSequence > xSequence( aSequences[nI]->getValues());
uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
OUString aRole;
if( ( xSeqProp->getPropertyValue(
OUString( "Role" )) >>= aRole ) &&
aRole.match( aRolePrefix ) && aRole.indexOf(aDirection) >= 0 )
{
return xSequence;
}
}
}
return Reference< chart2::data::XDataSequence > ();
}
}
void ChartExport::exportErrorBar(Reference< XPropertySet> xErrorBarProps, bool bYError)
{
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_errBars ),
FSEND );
pFS->singleElement( FSNS( XML_c, XML_errDir ),
XML_val, bYError ? "y" : "x",
FSEND );
bool bPositive, bNegative;
xErrorBarProps->getPropertyValue("ShowPositiveError") >>= bPositive;
xErrorBarProps->getPropertyValue("ShowNegativeError") >>= bNegative;
const char* pErrBarType;
if(bPositive && bNegative)
pErrBarType = "both";
else if(bPositive)
pErrBarType = "plus";
else if(bNegative)
pErrBarType = "minus";
else
{
// what the hell should we do now?
// at least this makes the file valid
pErrBarType = "both";
}
pFS->singleElement( FSNS( XML_c, XML_errBarType ),
XML_val, pErrBarType,
FSEND );
sal_Int32 nErrorBarStyle;
xErrorBarProps->getPropertyValue("ErrorBarStyle") >>= nErrorBarStyle;
const char* pErrorBarStyle = getErrorBarStyle(nErrorBarStyle);
pFS->singleElement( FSNS( XML_c, XML_errValType ),
XML_val, pErrorBarStyle,
FSEND );
pFS->singleElement( FSNS( XML_c, XML_noEndCap ),
XML_val, "0",
FSEND );
if(nErrorBarStyle == cssc::ErrorBarStyle::FROM_DATA)
{
uno::Reference< chart2::data::XDataSource > xDataSource(xErrorBarProps, uno::UNO_QUERY);
Sequence< Reference < chart2::data::XLabeledDataSequence > > aSequences =
xDataSource->getDataSequences();
if(bPositive)
{
exportSeriesValues(getLabeledSequence(aSequences, true), XML_plus);
}
if(bNegative)
{
exportSeriesValues(getLabeledSequence(aSequences, false), XML_minus);
}
}
else
{
double nVal;
if(nErrorBarStyle == cssc::ErrorBarStyle::STANDARD_DEVIATION)
{
xErrorBarProps->getPropertyValue("Weight") >>= nVal;
}
else
{
if(bPositive)
xErrorBarProps->getPropertyValue("PositiveError") >>= nVal;
else
xErrorBarProps->getPropertyValue("NegativeError") >>= nVal;
}
OString aVal = OString::number(nVal);
pFS->singleElement( FSNS( XML_c, XML_val ),
XML_val, aVal.getStr(),
FSEND );
}
pFS->endElement( FSNS( XML_c, XML_errBars) );
}
void ChartExport::exportView3D()
{
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
if( !xPropSet.is() )
return;
FSHelperPtr pFS = GetFS();
pFS->startElement( FSNS( XML_c, XML_view3D ),
FSEND );
// rotX
if( GetProperty( xPropSet, "RotationHorizontal" ) )
{
sal_Int32 nRotationX = 0;
mAny >>= nRotationX;
// X rotation (map Chart2 [-179,180] to OOXML [0..359])
if( nRotationX < 0 )
nRotationX += 360;
pFS->singleElement( FSNS( XML_c, XML_rotX ),
XML_val, I32S( nRotationX ),
FSEND );
}
// rotY
if( GetProperty( xPropSet, "RotationVertical" ) )
{
sal_Int32 nRotationY = 0;
mAny >>= nRotationY;
// Y rotation (map Chart2 [-179,180] to OOXML [0..359])
if( nRotationY < 0 )
nRotationY += 360;
pFS->singleElement( FSNS( XML_c, XML_rotY ),
XML_val, I32S( nRotationY ),
FSEND );
}
// rAngAx
if( GetProperty( xPropSet, "RightAngledAxes" ) )
{
sal_Bool bRightAngled = sal_False;
mAny >>= bRightAngled;
const char* sRightAngled = bRightAngled ? "1":"0";
pFS->singleElement( FSNS( XML_c, XML_rAngAx ),
XML_val, sRightAngled,
FSEND );
}
// perspective
if( GetProperty( xPropSet, "Perspective" ) )
{
sal_Int32 nPerspective = 0;
mAny >>= nPerspective;
// map Chart2 [0,100] to OOXML [0..200]
nPerspective *= 2;
pFS->singleElement( FSNS( XML_c, XML_perspective ),
XML_val, I32S( nPerspective ),
FSEND );
}
pFS->endElement( FSNS( XML_c, XML_view3D ) );
}
sal_Bool ChartExport::isDeep3dChart()
{
sal_Bool isDeep = sal_False;
if( mbIs3DChart )
{
Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
if( GetProperty( xPropSet, "Deep" ) )
mAny >>= isDeep;
}
return isDeep;
}
}// drawingml
}// oox
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */