1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <oox/token/namespaces.hxx>
21 #include <oox/token/tokens.hxx>
22 #include "oox/core/xmlfilterbase.hxx"
23 #include "oox/export/chartexport.hxx"
24 #include <oox/token/relationship.hxx>
25 #include "oox/export/utils.hxx"
26 #include "drawingml/chart/typegroupconverter.hxx"
30 #include <com/sun/star/awt/Gradient.hpp>
31 #include <com/sun/star/chart/XChartDocument.hpp>
32 #include <com/sun/star/chart/ChartLegendPosition.hpp>
33 #include <com/sun/star/chart/XTwoAxisXSupplier.hpp>
34 #include <com/sun/star/chart/XTwoAxisYSupplier.hpp>
35 #include <com/sun/star/chart/XAxisZSupplier.hpp>
36 #include <com/sun/star/chart/XChartDataArray.hpp>
37 #include <com/sun/star/chart/ChartDataRowSource.hpp>
38 #include <com/sun/star/chart/ChartAxisAssign.hpp>
39 #include <com/sun/star/chart/ChartSeriesAddress.hpp>
40 #include <com/sun/star/chart/X3DDisplay.hpp>
41 #include <com/sun/star/chart/XStatisticDisplay.hpp>
42 #include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
43 #include <com/sun/star/chart/ChartSymbolType.hpp>
44 #include <com/sun/star/chart/ChartAxisMarks.hpp>
45 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
46 #include <com/sun/star/chart/ChartAxisPosition.hpp>
47 #include <com/sun/star/chart/ChartSolidType.hpp>
48 #include <com/sun/star/chart/DataLabelPlacement.hpp>
49 #include <com/sun/star/chart/ErrorBarStyle.hpp>
50 #include <com/sun/star/chart/MissingValueTreatment.hpp>
52 #include <com/sun/star/chart2/RelativePosition.hpp>
53 #include <com/sun/star/chart2/RelativeSize.hpp>
54 #include <com/sun/star/chart2/XChartDocument.hpp>
55 #include <com/sun/star/chart2/XDiagram.hpp>
56 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
57 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
58 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
59 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
60 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
61 #include <com/sun/star/chart2/DataPointLabel.hpp>
62 #include <com/sun/star/chart2/Symbol.hpp>
63 #include <com/sun/star/chart2/data/XDataSource.hpp>
64 #include <com/sun/star/chart2/data/XDataSink.hpp>
65 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
66 #include <com/sun/star/chart2/data/XDataProvider.hpp>
67 #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
68 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
69 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
70 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
72 #include <com/sun/star/beans/XPropertySet.hpp>
73 #include <com/sun/star/drawing/XShape.hpp>
74 #include <com/sun/star/drawing/FillStyle.hpp>
75 #include <com/sun/star/drawing/BitmapMode.hpp>
76 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
77 #include <com/sun/star/lang/XServiceName.hpp>
79 #include <com/sun/star/table/CellAddress.hpp>
80 #include <com/sun/star/sheet/XFormulaParser.hpp>
81 #include <com/sun/star/sheet/FormulaToken.hpp>
82 #include <com/sun/star/sheet/AddressConvention.hpp>
84 #include <com/sun/star/text/WritingMode.hpp>
85 #include <com/sun/star/container/XNamed.hpp>
86 #include <com/sun/star/embed/XVisualObject.hpp>
87 #include <com/sun/star/embed/Aspects.hpp>
89 #include <comphelper/processfactory.hxx>
90 #include <comphelper/random.hxx>
91 #include <comphelper/sequence.hxx>
92 #include <xmloff/SchXMLSeriesHelper.hxx>
93 #include "ColorPropertySet.hxx"
95 #include <svl/zforlist.hxx>
96 #include <svl/numuno.hxx>
99 #include <unordered_set>
101 #include <rtl/math.hxx>
104 using namespace css::uno
;
105 using namespace css::drawing
;
106 using namespace ::oox::core
;
107 using css::beans::PropertyValue
;
108 using css::beans::XPropertySet
;
109 using css::container::XNamed
;
110 using css::table::CellAddress
;
111 using css::sheet::XFormulaParser
;
112 using ::oox::core::XmlFilterBase
;
113 using ::sax_fastparser::FSHelperPtr
;
115 namespace cssc
= css::chart
;
117 namespace oox
{ namespace drawingml
{
121 bool isPrimaryAxes(sal_Int32 nIndex
)
123 assert(nIndex
== 0 || nIndex
== 1);
129 class lcl_MatchesRole
: public ::std::unary_function
< Reference
< chart2::data::XLabeledDataSequence
>, bool >
132 explicit lcl_MatchesRole( const OUString
& aRole
) :
136 bool operator () ( const Reference
< chart2::data::XLabeledDataSequence
> & xSeq
) const
140 Reference
< beans::XPropertySet
> xProp( xSeq
->getValues(), uno::UNO_QUERY
);
143 return ( xProp
.is() &&
144 (xProp
->getPropertyValue( "Role" ) >>= aRole
) &&
145 m_aRole
.equals( aRole
));
152 template< typename T
>
153 void lcl_SequenceToVectorAppend( const Sequence
< T
> & rSource
, ::std::vector
< T
> & rDestination
)
155 rDestination
.reserve( rDestination
.size() + rSource
.getLength());
156 ::std::copy( rSource
.begin(), rSource
.end(),
157 ::std::back_inserter( rDestination
));
160 Reference
< chart2::data::XLabeledDataSequence
> lcl_getCategories( const Reference
< chart2::XDiagram
> & xDiagram
)
162 Reference
< chart2::data::XLabeledDataSequence
> xResult
;
165 Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt(
166 xDiagram
, uno::UNO_QUERY_THROW
);
167 Sequence
< Reference
< chart2::XCoordinateSystem
> > aCooSysSeq(
168 xCooSysCnt
->getCoordinateSystems());
169 for( sal_Int32 i
=0; i
<aCooSysSeq
.getLength(); ++i
)
171 Reference
< chart2::XCoordinateSystem
> xCooSys( aCooSysSeq
[i
] );
172 OSL_ASSERT( xCooSys
.is());
173 for( sal_Int32 nN
= xCooSys
->getDimension(); nN
--; )
175 const sal_Int32 nMaxAxisIndex
= xCooSys
->getMaximumAxisIndexByDimension(nN
);
176 for(sal_Int32 nI
=0; nI
<=nMaxAxisIndex
; ++nI
)
178 Reference
< chart2::XAxis
> xAxis
= xCooSys
->getAxisByDimension( nN
, nI
);
179 OSL_ASSERT( xAxis
.is());
182 chart2::ScaleData aScaleData
= xAxis
->getScaleData();
183 if( aScaleData
.Categories
.is())
185 xResult
.set( aScaleData
.Categories
);
193 catch( const uno::Exception
& ex
)
195 (void)ex
; // avoid warning for pro build
196 OSL_FAIL( OUStringToOString(
197 "Exception caught. Type: " +
198 OUString::createFromAscii( typeid( ex
).name()) +
200 ex
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr());
206 Reference
< chart2::data::XDataSource
> lcl_createDataSource(
207 const std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > & aData
)
209 Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
210 Reference
< chart2::data::XDataSink
> xSink(
211 xContext
->getServiceManager()->createInstanceWithContext(
212 "com.sun.star.chart2.data.DataSource", xContext
),
213 uno::UNO_QUERY_THROW
);
215 xSink
->setData( comphelper::containerToSequence(aData
) );
217 return Reference
< chart2::data::XDataSource
>( xSink
, uno::UNO_QUERY
);
220 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > lcl_getAllSeriesSequences( const Reference
< chart2::XChartDocument
>& xChartDoc
)
222 ::std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aContainer
;
225 Reference
< chart2::XDiagram
> xDiagram( xChartDoc
->getFirstDiagram());
226 ::std::vector
< Reference
< chart2::XDataSeries
> > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram
));
227 for( ::std::vector
< Reference
< chart2::XDataSeries
> >::const_iterator
aSeriesIt( aSeriesVector
.begin() )
228 ; aSeriesIt
!= aSeriesVector
.end(); ++aSeriesIt
)
230 Reference
< chart2::data::XDataSource
> xDataSource( *aSeriesIt
, uno::UNO_QUERY
);
231 if( !xDataSource
.is() )
233 uno::Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
234 lcl_SequenceToVectorAppend( aDataSequences
, aContainer
);
238 return comphelper::containerToSequence(aContainer
);
241 Reference
< chart2::data::XLabeledDataSequence
>
242 lcl_getDataSequenceByRole(
243 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > & aLabeledSeq
,
244 const OUString
& rRole
)
246 Reference
< chart2::data::XLabeledDataSequence
> aNoResult
;
248 const Reference
< chart2::data::XLabeledDataSequence
> * pBegin
= aLabeledSeq
.getConstArray();
249 const Reference
< chart2::data::XLabeledDataSequence
> * pEnd
= pBegin
+ aLabeledSeq
.getLength();
250 const Reference
< chart2::data::XLabeledDataSequence
> * pMatch
=
251 ::std::find_if( pBegin
, pEnd
, lcl_MatchesRole( rRole
));
259 Reference
< chart2::data::XDataSource
> lcl_pressUsedDataIntoRectangularFormat( const Reference
< chart2::XChartDocument
>& xChartDoc
, bool& rOutSourceHasCategoryLabels
)
261 ::std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aLabeledSeqVector
;
263 //categories are always the first sequence
264 Reference
< chart2::XDiagram
> xDiagram( xChartDoc
->getFirstDiagram());
265 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( xDiagram
) );
266 if( xCategories
.is() )
267 aLabeledSeqVector
.push_back( xCategories
);
268 rOutSourceHasCategoryLabels
= xCategories
.is();
270 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeriesSeqVector(
271 lcl_getAllSeriesSequences( xChartDoc
) );
273 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
274 Reference
< chart2::data::XLabeledDataSequence
> xXValues(
275 lcl_getDataSequenceByRole( aSeriesSeqVector
, "values-x" ) );
277 aLabeledSeqVector
.push_back( xXValues
);
279 //add all other sequences now without x-values
280 lcl_MatchesRole
aHasXValues( "values-x" );
281 for( sal_Int32 nN
=0; nN
<aSeriesSeqVector
.getLength(); nN
++ )
283 if( !aHasXValues( aSeriesSeqVector
[nN
] ) )
284 aLabeledSeqVector
.push_back( aSeriesSeqVector
[nN
] );
287 return lcl_createDataSource( aLabeledSeqVector
);
290 bool lcl_isSeriesAttachedToFirstAxis(
291 const Reference
< chart2::XDataSeries
> & xDataSeries
)
297 sal_Int32 nAxisIndex
= 0;
298 Reference
< beans::XPropertySet
> xProp( xDataSeries
, uno::UNO_QUERY_THROW
);
300 xProp
->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex
;
301 bResult
= (0==nAxisIndex
);
303 catch( const uno::Exception
& ex
)
305 (void)ex
; // avoid warning for pro build
306 OSL_FAIL( OUStringToOString(
307 "Exception caught. Type: " +
308 OUString::createFromAscii( typeid( ex
).name()) +
310 ex
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr());
316 OUString
lcl_flattenStringSequence( const Sequence
< OUString
> & rSequence
)
318 OUStringBuffer aResult
;
319 bool bPrecedeWithSpace
= false;
320 for( sal_Int32 nIndex
=0; nIndex
<rSequence
.getLength(); ++nIndex
)
322 if( !rSequence
[nIndex
].isEmpty())
324 if( bPrecedeWithSpace
)
325 aResult
.append( ' ' );
326 aResult
.append( rSequence
[nIndex
] );
327 bPrecedeWithSpace
= true;
330 return aResult
.makeStringAndClear();
333 OUString
lcl_getLabelString( const Reference
< chart2::data::XDataSequence
> & xLabelSeq
)
335 Sequence
< OUString
> aLabels
;
337 uno::Reference
< chart2::data::XTextualDataSequence
> xTextualDataSequence( xLabelSeq
, uno::UNO_QUERY
);
338 if( xTextualDataSequence
.is())
340 aLabels
= xTextualDataSequence
->getTextualData();
342 else if( xLabelSeq
.is())
344 Sequence
< uno::Any
> aAnies( xLabelSeq
->getData());
345 aLabels
.realloc( aAnies
.getLength());
346 for( sal_Int32 i
=0; i
<aAnies
.getLength(); ++i
)
347 aAnies
[i
] >>= aLabels
[i
];
350 return lcl_flattenStringSequence( aLabels
);
353 void lcl_fillCategoriesIntoStringVector(
354 const Reference
< chart2::data::XDataSequence
> & xCategories
,
355 ::std::vector
< OUString
> & rOutCategories
)
357 OSL_ASSERT( xCategories
.is());
358 if( !xCategories
.is())
360 Reference
< chart2::data::XTextualDataSequence
> xTextualDataSequence( xCategories
, uno::UNO_QUERY
);
361 if( xTextualDataSequence
.is())
363 rOutCategories
.clear();
364 Sequence
< OUString
> aTextData( xTextualDataSequence
->getTextualData());
365 ::std::copy( aTextData
.begin(), aTextData
.end(),
366 ::std::back_inserter( rOutCategories
));
370 Sequence
< uno::Any
> aAnies( xCategories
->getData());
371 rOutCategories
.resize( aAnies
.getLength());
372 for( sal_Int32 i
=0; i
<aAnies
.getLength(); ++i
)
373 aAnies
[i
] >>= rOutCategories
[i
];
377 ::std::vector
< double > lcl_getAllValuesFromSequence( const Reference
< chart2::data::XDataSequence
> & xSeq
)
380 ::rtl::math::setNan( &fNan
);
381 ::std::vector
< double > aResult
;
383 Reference
< chart2::data::XNumericalDataSequence
> xNumSeq( xSeq
, uno::UNO_QUERY
);
386 Sequence
< double > aValues( xNumSeq
->getNumericalData());
387 ::std::copy( aValues
.begin(), aValues
.end(),
388 ::std::back_inserter( aResult
));
392 Sequence
< uno::Any
> aAnies( xSeq
->getData());
393 aResult
.resize( aAnies
.getLength(), fNan
);
394 for( sal_Int32 i
=0; i
<aAnies
.getLength(); ++i
)
395 aAnies
[i
] >>= aResult
[i
];
400 sal_Int32
lcl_getChartType( const OUString
& sChartType
)
402 chart::TypeId eChartTypeId
= chart::TYPEID_UNKNOWN
;
403 if( sChartType
== "com.sun.star.chart.BarDiagram"
404 || sChartType
== "com.sun.star.chart2.ColumnChartType" )
405 eChartTypeId
= chart::TYPEID_BAR
;
406 else if( sChartType
== "com.sun.star.chart.AreaDiagram"
407 || sChartType
== "com.sun.star.chart2.AreaChartType" )
408 eChartTypeId
= chart::TYPEID_AREA
;
409 else if( sChartType
== "com.sun.star.chart.LineDiagram"
410 || sChartType
== "com.sun.star.chart2.LineChartType" )
411 eChartTypeId
= chart::TYPEID_LINE
;
412 else if( sChartType
== "com.sun.star.chart.PieDiagram"
413 || sChartType
== "com.sun.star.chart2.PieChartType" )
414 eChartTypeId
= chart::TYPEID_PIE
;
415 else if( sChartType
== "com.sun.star.chart.DonutDiagram"
416 || sChartType
== "com.sun.star.chart2.DonutChartType" )
417 eChartTypeId
= chart::TYPEID_DOUGHNUT
;
418 else if( sChartType
== "com.sun.star.chart.XYDiagram"
419 || sChartType
== "com.sun.star.chart2.ScatterChartType" )
420 eChartTypeId
= chart::TYPEID_SCATTER
;
421 else if( sChartType
== "com.sun.star.chart.NetDiagram"
422 || sChartType
== "com.sun.star.chart2.NetChartType" )
423 eChartTypeId
= chart::TYPEID_RADARLINE
;
424 else if( sChartType
== "com.sun.star.chart.FilledNetDiagram"
425 || sChartType
== "com.sun.star.chart2.FilledNetChartType" )
426 eChartTypeId
= chart::TYPEID_RADARAREA
;
427 else if( sChartType
== "com.sun.star.chart.StockDiagram"
428 || sChartType
== "com.sun.star.chart2.CandleStickChartType" )
429 eChartTypeId
= chart::TYPEID_STOCK
;
430 else if( sChartType
== "com.sun.star.chart.BubbleDiagram"
431 || sChartType
== "com.sun.star.chart2.BubbleChartType" )
432 eChartTypeId
= chart::TYPEID_BUBBLE
;
437 sal_Int32
lcl_generateRandomValue()
439 return comphelper::rng::uniform_int_distribution(0, 100000000-1);
442 ChartExport::ChartExport( sal_Int32 nXmlNamespace
, FSHelperPtr pFS
, Reference
< frame::XModel
>& xModel
, XmlFilterBase
* pFB
, DocumentType eDocumentType
)
443 : DrawingML( pFS
, pFB
, eDocumentType
)
444 , mnXmlNamespace( nXmlNamespace
)
446 , mxChartModel( xModel
)
447 , mbHasCategoryLabels( false )
448 , mbHasZAxis( false )
449 , mbIs3DChart( false )
455 sal_Int32
ChartExport::GetChartID( )
457 sal_Int32 nID
= GetFB()->GetUniqueId();
461 sal_Int32
ChartExport::getChartType( )
463 OUString sChartType
= mxDiagram
->getDiagramType();
464 return lcl_getChartType( sChartType
);
467 OUString
ChartExport::parseFormula( const OUString
& rRange
)
470 Reference
< XFormulaParser
> xParser
;
471 uno::Reference
< lang::XMultiServiceFactory
> xSF( GetFB()->getModelFactory(), uno::UNO_QUERY
);
476 xParser
.set( xSF
->createInstance("com.sun.star.sheet.FormulaParser"), UNO_QUERY
);
483 SAL_WARN_IF(!xParser
.is(), "oox", "creating formula parser failed");
487 Reference
< XPropertySet
> xParserProps( xParser
, uno::UNO_QUERY
);
488 if( xParserProps
.is() )
490 xParserProps
->setPropertyValue("FormulaConvention", uno::makeAny(css::sheet::AddressConvention::OOO
) );
492 uno::Sequence
<sheet::FormulaToken
> aTokens
= xParser
->parseFormula( rRange
, CellAddress( 0, 0, 0 ) );
493 if( xParserProps
.is() )
495 xParserProps
->setPropertyValue("FormulaConvention", uno::makeAny(css::sheet::AddressConvention::XL_OOX
) );
497 aResult
= xParser
->printFormula( aTokens
, CellAddress( 0, 0, 0 ) );
501 //FIXME: currently just using simple converter, e.g $Sheet1.$A$1:$C$1 -> Sheet1!$A$1:$C$1
502 OUString
aRange( rRange
);
503 if( aRange
.startsWith("$") )
504 aRange
= aRange
.copy(1);
505 aRange
= aRange
.replaceAll(".$", "!$" );
512 void ChartExport::WriteChartObj( const Reference
< XShape
>& xShape
, sal_Int32 nChartCount
)
514 FSHelperPtr pFS
= GetFS();
516 pFS
->startElementNS( mnXmlNamespace
, XML_graphicFrame
, FSEND
);
518 pFS
->startElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
, FSEND
);
520 // TODO: get the correct chart name chart id
521 OUString sName
= "Object 1";
522 Reference
< XNamed
> xNamed( xShape
, UNO_QUERY
);
524 sName
= xNamed
->getName();
526 sal_Int32 nID
= GetChartID();
528 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
530 XML_name
, USS( sName
),
533 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvGraphicFramePr
,
536 if( GetDocumentType() == DOCUMENT_PPTX
)
537 pFS
->singleElementNS( mnXmlNamespace
, XML_nvPr
,
539 pFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
541 // visual chart properties
542 WriteShapeTransformation( xShape
, mnXmlNamespace
);
544 // writer chart object
545 pFS
->startElement( FSNS( XML_a
, XML_graphic
), FSEND
);
546 pFS
->startElement( FSNS( XML_a
, XML_graphicData
),
547 XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/chart",
550 const char* sFullPath
= nullptr;
551 const char* sRelativePath
= nullptr;
552 switch( GetDocumentType() )
556 sFullPath
= "word/charts/chart";
557 sRelativePath
= "charts/chart";
562 sFullPath
= "ppt/charts/chart";
563 sRelativePath
= "../charts/chart";
568 sFullPath
= "xl/charts/chart";
569 sRelativePath
= "../charts/chart";
574 sFullPath
= "charts/chart";
575 sRelativePath
= "charts/chart";
579 OUString sFullStream
= OUStringBuffer()
580 .appendAscii(sFullPath
)
583 .makeStringAndClear();
584 OUString sRelativeStream
= OUStringBuffer()
585 .appendAscii(sRelativePath
)
588 .makeStringAndClear();
589 FSHelperPtr pChart
= CreateOutputStream(
592 pFS
->getOutputStream(),
593 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
594 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
597 XmlFilterBase
* pFB
= GetFB();
598 pFS
->singleElement( FSNS( XML_c
, XML_chart
),
599 FSNS( XML_xmlns
, XML_c
), OUStringToOString(pFB
->getNamespaceURL(OOX_NS(dmlChart
)), RTL_TEXTENCODING_UTF8
).getStr(),
600 FSNS( XML_xmlns
, XML_r
), OUStringToOString(pFB
->getNamespaceURL(OOX_NS(officeRel
)), RTL_TEXTENCODING_UTF8
).getStr(),
601 FSNS( XML_r
, XML_id
), USS( sId
),
604 pFS
->endElement( FSNS( XML_a
, XML_graphicData
) );
605 pFS
->endElement( FSNS( XML_a
, XML_graphic
) );
606 pFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
612 void ChartExport::InitRangeSegmentationProperties( const Reference
< chart2::XChartDocument
> & xChartDoc
)
617 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
618 OSL_ENSURE( xDataProvider
.is(), "No DataProvider" );
619 if( xDataProvider
.is())
621 Reference
< chart2::data::XDataSource
> xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc
, mbHasCategoryLabels
));
622 Sequence
< beans::PropertyValue
> aArgs( xDataProvider
->detectArguments( xDataSource
));
623 OUString sCellRange
, sBrokenRange
;
624 bool bBrokenRangeAvailable
= false;
625 for( sal_Int32 i
=0; i
<aArgs
.getLength(); ++i
)
627 if ( aArgs
[i
].Name
== "CellRangeRepresentation" )
628 aArgs
[i
].Value
>>= sCellRange
;
629 else if ( aArgs
[i
].Name
== "BrokenCellRangeForExport" )
631 if( aArgs
[i
].Value
>>= sBrokenRange
)
632 bBrokenRangeAvailable
= true;
636 // #i79009# For Writer we have to export a broken version of the
637 // range, where every row number is noe too large, so that older
638 // version can correctly read those files.
639 msChartAddress
= (bBrokenRangeAvailable
? sBrokenRange
: sCellRange
);
640 if( !msChartAddress
.isEmpty() )
642 // convert format to XML-conform one
643 Reference
< chart2::data::XRangeXMLConversion
> xConversion( xDataProvider
, uno::UNO_QUERY
);
644 if( xConversion
.is())
645 msChartAddress
= xConversion
->convertRangeToXML( msChartAddress
);
649 catch( const uno::Exception
& ex
)
651 (void)ex
; // avoid warning for pro build
652 OSL_FAIL( OUStringToOString(
653 "Exception caught. Type: " +
654 OUString::createFromAscii( typeid( ex
).name()) +
656 ex
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr());
660 void ChartExport::ExportContent()
662 Reference
< chart2::XChartDocument
> xChartDoc( getModel(), uno::UNO_QUERY
);
663 OSL_ASSERT( xChartDoc
.is() );
664 if( !xChartDoc
.is() )
666 InitRangeSegmentationProperties( xChartDoc
);
667 // TODO: export chart
671 void ChartExport::ExportContent_()
673 Reference
< css::chart::XChartDocument
> xChartDoc( getModel(), uno::UNO_QUERY
);
676 // determine if data comes from the outside
677 bool bIncludeTable
= true;
679 Reference
< chart2::XChartDocument
> xNewDoc( xChartDoc
, uno::UNO_QUERY
);
682 // check if we have own data. If so we must not export the complete
683 // range string, as this is our only indicator for having own or
684 // external data. @todo: fix this in the file format!
685 Reference
< lang::XServiceInfo
> xDPServiceInfo( xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
686 if( ! (xDPServiceInfo
.is() && xDPServiceInfo
->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
688 bIncludeTable
= false;
693 Reference
< lang::XServiceInfo
> xServ( xChartDoc
, uno::UNO_QUERY
);
696 if( xServ
->supportsService("com.sun.star.chart.ChartTableAddressSupplier"))
698 Reference
< beans::XPropertySet
> xProp( xServ
, uno::UNO_QUERY
);
704 OUString sChartAddress
;
705 aAny
= xProp
->getPropertyValue("ChartRangeAddress");
706 aAny
>>= msChartAddress
;
707 //maExportHelper.SetChartRangeAddress( sChartAddress );
709 //maExportHelper.SetTableNumberList( sTableNumberList );
711 // do not include own table if there are external addresses
712 bIncludeTable
= sChartAddress
.isEmpty();
714 catch( beans::UnknownPropertyException
& )
716 OSL_FAIL( "Property ChartRangeAddress not supported by ChartDocument" );
722 exportChartSpace( xChartDoc
, bIncludeTable
);
726 OSL_FAIL( "Couldn't export chart due to wrong XModel" );
730 void ChartExport::exportChartSpace( const Reference
< css::chart::XChartDocument
>& xChartDoc
,
733 FSHelperPtr pFS
= GetFS();
734 XmlFilterBase
* pFB
= GetFB();
735 pFS
->startElement( FSNS( XML_c
, XML_chartSpace
),
736 FSNS( XML_xmlns
, XML_c
), OUStringToOString(pFB
->getNamespaceURL(OOX_NS(dmlChart
)), RTL_TEXTENCODING_UTF8
).getStr(),
737 FSNS( XML_xmlns
, XML_a
), OUStringToOString(pFB
->getNamespaceURL(OOX_NS(dml
)), RTL_TEXTENCODING_UTF8
).getStr(),
738 FSNS( XML_xmlns
, XML_r
), OUStringToOString(pFB
->getNamespaceURL(OOX_NS(officeRel
)), RTL_TEXTENCODING_UTF8
).getStr(),
740 // TODO: get the correct editing language
741 pFS
->singleElement( FSNS( XML_c
, XML_lang
),
745 pFS
->singleElement(FSNS( XML_c
, XML_roundedCorners
),
751 // TODO:external data
754 exportChart(xChartDoc
);
756 // TODO: printSettings
758 // TODO: text properties
759 // TODO: shape properties
760 Reference
< XPropertySet
> xPropSet( xChartDoc
->getArea(), uno::UNO_QUERY
);
762 exportShapeProps( xPropSet
);
765 exportExternalData(xChartDoc
);
767 pFS
->endElement( FSNS( XML_c
, XML_chartSpace
) );
770 void ChartExport::exportExternalData( const Reference
< css::chart::XChartDocument
>& xChartDoc
)
772 // Embedded external data is grab bagged for docx file hence adding export part of
773 // external data for docx files only.
774 if(GetDocumentType() != DOCUMENT_DOCX
)
777 OUString externalDataPath
;
778 Reference
< beans::XPropertySet
> xDocPropSet( xChartDoc
->getDiagram(), uno::UNO_QUERY
);
779 if( xDocPropSet
.is())
783 Any
aAny( xDocPropSet
->getPropertyValue( "ExternalData" ));
784 aAny
>>= externalDataPath
;
786 catch( beans::UnknownPropertyException
& )
788 SAL_WARN("oox", "Required property not found in ChartDocument");
791 if(!externalDataPath
.isEmpty())
793 // Here adding external data entry to relationship.
794 OUString relationPath
= externalDataPath
;
795 // Converting absolute path to relative path.
796 if( externalDataPath
[ 0 ] != '.' && externalDataPath
[ 1 ] != '.')
798 sal_Int32 nStartPos
= 0;
799 sal_Int32 nSepPos
= externalDataPath
.indexOf( '/', nStartPos
);
802 relationPath
= relationPath
.copy( nSepPos
, ::std::max
< sal_Int32
>( externalDataPath
.getLength(), 0 ) - nSepPos
);
803 relationPath
= OUStringBuffer( ".." ).append( relationPath
).makeStringAndClear();
806 FSHelperPtr pFS
= GetFS();
807 OUString type
= oox::getRelationship(Relationship::PACKAGE
);
808 if (relationPath
.endsWith(".bin"))
809 type
= oox::getRelationship(Relationship::OLEOBJECT
);
811 OUString sRelId
= GetFB()->addRelation(pFS
->getOutputStream(),
814 pFS
->singleElementNS( XML_c
, XML_externalData
,
815 FSNS(XML_r
, XML_id
), OUStringToOString(sRelId
, RTL_TEXTENCODING_UTF8
),
820 void ChartExport::exportChart( const Reference
< css::chart::XChartDocument
>& xChartDoc
)
822 Reference
< chart2::XChartDocument
> xNewDoc( xChartDoc
, uno::UNO_QUERY
);
823 mxDiagram
.set( xChartDoc
->getDiagram() );
825 mxNewDiagram
.set( xNewDoc
->getFirstDiagram());
827 // get Properties of ChartDocument
828 bool bHasMainTitle
= false;
829 bool bHasLegend
= false;
830 Reference
< beans::XPropertySet
> xDocPropSet( xChartDoc
, uno::UNO_QUERY
);
831 if( xDocPropSet
.is())
835 bool bHasSubTitle
= false;
836 Any
aAny( xDocPropSet
->getPropertyValue("HasMainTitle"));
837 aAny
>>= bHasMainTitle
;
838 aAny
= xDocPropSet
->getPropertyValue("HasSubTitle");
839 aAny
>>= bHasSubTitle
;
840 aAny
= xDocPropSet
->getPropertyValue("HasLegend");
843 catch( beans::UnknownPropertyException
& )
845 SAL_WARN("oox", "Required property not found in ChartDocument");
847 } // if( xDocPropSet.is())
851 FSHelperPtr pFS
= GetFS();
852 pFS
->startElement( FSNS( XML_c
, XML_chart
),
858 Reference
< drawing::XShape
> xShape
= xChartDoc
->getTitle();
861 exportTitle( xShape
);
862 pFS
->singleElement( FSNS(XML_c
, XML_autoTitleDeleted
),
873 Reference
< beans::XPropertySet
> xFloor( mxNewDiagram
->getFloor(), uno::UNO_QUERY
);
876 pFS
->startElement( FSNS( XML_c
, XML_floor
),
878 exportShapeProps( xFloor
);
879 pFS
->endElement( FSNS( XML_c
, XML_floor
) );
885 Reference
< beans::XPropertySet
> xBackWall( mxNewDiagram
->getWall(), uno::UNO_QUERY
);
888 pFS
->startElement( FSNS( XML_c
, XML_backWall
),
890 exportShapeProps( xBackWall
);
891 pFS
->endElement( FSNS( XML_c
, XML_backWall
) );
899 exportLegend( xChartDoc
);
901 uno::Reference
<beans::XPropertySet
> xDiagramPropSet(xChartDoc
->getDiagram(), uno::UNO_QUERY
);
902 uno::Any aPlotVisOnly
= xDiagramPropSet
->getPropertyValue("IncludeHiddenCells");
903 bool bIncludeHiddenCells
= false;
904 aPlotVisOnly
>>= bIncludeHiddenCells
;
905 pFS
->singleElement( FSNS( XML_c
, XML_plotVisOnly
),
906 XML_val
, BS(!bIncludeHiddenCells
),
909 exportMissingValueTreatment(Reference
<beans::XPropertySet
>(mxDiagram
, uno::UNO_QUERY
));
911 pFS
->endElement( FSNS( XML_c
, XML_chart
) );
914 void ChartExport::exportMissingValueTreatment(const uno::Reference
<beans::XPropertySet
>& xPropSet
)
920 uno::Any aAny
= xPropSet
->getPropertyValue("MissingValueTreatment");
921 if (!(aAny
>>= nVal
))
924 const char* pVal
= nullptr;
927 case cssc::MissingValueTreatment::LEAVE_GAP
:
930 case cssc::MissingValueTreatment::USE_ZERO
:
933 case cssc::MissingValueTreatment::CONTINUE
:
937 SAL_WARN("oox", "unknown MissingValueTreatment value");
941 FSHelperPtr pFS
= GetFS();
942 pFS
->singleElement( FSNS(XML_c
, XML_dispBlanksAs
),
947 void ChartExport::exportLegend( const Reference
< css::chart::XChartDocument
>& xChartDoc
)
949 FSHelperPtr pFS
= GetFS();
950 pFS
->startElement( FSNS( XML_c
, XML_legend
),
953 Reference
< beans::XPropertySet
> xProp( xChartDoc
->getLegend(), uno::UNO_QUERY
);
957 css::chart::ChartLegendPosition aLegendPos
= css::chart::ChartLegendPosition_NONE
;
960 Any
aAny( xProp
->getPropertyValue( "Alignment" ));
963 catch( beans::UnknownPropertyException
& )
965 SAL_WARN("oox", "Property Align not found in ChartLegend");
968 const char* strPos
= nullptr;
971 case css::chart::ChartLegendPosition_LEFT
:
974 case css::chart::ChartLegendPosition_RIGHT
:
977 case css::chart::ChartLegendPosition_TOP
:
980 case css::chart::ChartLegendPosition_BOTTOM
:
983 case css::chart::ChartLegendPosition_NONE
:
984 case css::chart::ChartLegendPosition::ChartLegendPosition_MAKE_FIXED_SIZE
:
989 if( strPos
!= nullptr )
991 pFS
->singleElement( FSNS( XML_c
, XML_legendPos
),
996 uno::Any aRelativePos
= xProp
->getPropertyValue("RelativePosition");
997 if (aRelativePos
.hasValue())
999 chart2::RelativePosition aPos
= aRelativePos
.get
<chart2::RelativePosition
>();
1000 pFS
->startElement(FSNS(XML_c
, XML_layout
), FSEND
);
1001 pFS
->startElement(FSNS(XML_c
, XML_manualLayout
), FSEND
);
1003 pFS
->singleElement(FSNS(XML_c
, XML_xMode
),
1006 pFS
->singleElement(FSNS(XML_c
, XML_yMode
),
1010 double x
= aPos
.Primary
;
1011 double y
= aPos
.Secondary
;
1013 pFS
->singleElement(FSNS(XML_c
, XML_x
),
1016 pFS
->singleElement(FSNS(XML_c
, XML_y
),
1019 SAL_WARN_IF(aPos
.Anchor
!= css::drawing::Alignment_TOP_LEFT
, "oox", "unsupported anchor position");
1021 pFS
->endElement(FSNS(XML_c
, XML_manualLayout
));
1022 pFS
->endElement(FSNS(XML_c
, XML_layout
));
1025 if (strPos
!= nullptr)
1027 pFS
->singleElement( FSNS( XML_c
, XML_overlay
),
1033 exportShapeProps( xProp
);
1038 pFS
->endElement( FSNS( XML_c
, XML_legend
) );
1044 * nRotation is a 100th of a degree and the return value is
1045 * in a 60,000th of a degree
1047 * Also rotation is in opposite directions so multiply with -1
1049 OString
calcRotationValue(sal_Int32 nRotation
)
1051 if (nRotation
> 18000) // 180 degree
1056 return OString::number(nRotation
);
1061 void ChartExport::exportTitle( const Reference
< XShape
>& xShape
)
1064 Reference
< beans::XPropertySet
> xPropSet( xShape
, uno::UNO_QUERY
);
1067 xPropSet
->getPropertyValue("String") >>= sText
;
1069 if( sText
.isEmpty() )
1072 FSHelperPtr pFS
= GetFS();
1073 pFS
->startElement( FSNS( XML_c
, XML_title
),
1076 pFS
->startElement( FSNS( XML_c
, XML_tx
),
1078 pFS
->startElement( FSNS( XML_c
, XML_rich
),
1082 const char* sWritingMode
= nullptr;
1083 bool bVertical
= false;
1084 xPropSet
->getPropertyValue("StackedText") >>= bVertical
;
1086 sWritingMode
= "wordArtVert";
1088 sal_Int32 nRotation
= 0;
1089 xPropSet
->getPropertyValue("TextRotation") >>= nRotation
;
1091 pFS
->singleElement( FSNS( XML_a
, XML_bodyPr
),
1092 XML_vert
, sWritingMode
,
1093 XML_rot
, calcRotationValue(nRotation
).getStr(),
1096 pFS
->singleElement( FSNS( XML_a
, XML_lstStyle
),
1098 // FIXME: handle multiple paragraphs to parse aText
1099 pFS
->startElement( FSNS( XML_a
, XML_p
),
1102 pFS
->startElement( FSNS( XML_a
, XML_pPr
),
1105 bool bDummy
= false;
1107 WriteRunProperties(xPropSet
, false, XML_defRPr
, true, bDummy
, nDummy
);
1109 pFS
->endElement( FSNS( XML_a
, XML_pPr
) );
1111 pFS
->startElement( FSNS( XML_a
, XML_r
),
1114 WriteRunProperties( xPropSet
, false, XML_rPr
, true, bDummy
, nDummy
);
1115 pFS
->startElement( FSNS( XML_a
, XML_t
),
1117 pFS
->writeEscaped( sText
);
1118 pFS
->endElement( FSNS( XML_a
, XML_t
) );
1119 pFS
->endElement( FSNS( XML_a
, XML_r
) );
1121 pFS
->endElement( FSNS( XML_a
, XML_p
) );
1123 pFS
->endElement( FSNS( XML_c
, XML_rich
) );
1124 pFS
->endElement( FSNS( XML_c
, XML_tx
) );
1126 uno::Any aManualLayout
= xPropSet
->getPropertyValue("RelativePosition");
1127 if (aManualLayout
.hasValue())
1129 pFS
->startElement(FSNS( XML_c
, XML_layout
), FSEND
);
1130 pFS
->startElement(FSNS(XML_c
, XML_manualLayout
), FSEND
);
1131 pFS
->singleElement(FSNS(XML_c
, XML_xMode
),
1134 pFS
->singleElement(FSNS(XML_c
, XML_yMode
),
1138 Reference
<embed::XVisualObject
> xVisObject(mxChartModel
, uno::UNO_QUERY
);
1139 awt::Size aPageSize
= xVisObject
->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT
);
1141 // awt::Size aSize = xShape->getSize();
1142 awt::Point aPos2
= xShape
->getPosition();
1143 double x
= (double)aPos2
.X
/ (double) aPageSize
.Width
;
1144 double y
= (double)aPos2
.Y
/ (double) aPageSize
.Height
;
1146 pFS->singleElement(FSNS(XML_c, XML_wMode),
1149 pFS->singleElement(FSNS(XML_c, XML_hMode),
1153 pFS
->singleElement(FSNS(XML_c
, XML_x
),
1156 pFS
->singleElement(FSNS(XML_c
, XML_y
),
1160 pFS->singleElement(FSNS(XML_c, XML_w),
1163 pFS->singleElement(FSNS(XML_c, XML_h),
1167 pFS
->endElement(FSNS(XML_c
, XML_manualLayout
));
1168 pFS
->endElement(FSNS(XML_c
, XML_layout
));
1171 pFS
->singleElement( FSNS(XML_c
, XML_overlay
),
1175 pFS
->endElement( FSNS( XML_c
, XML_title
) );
1178 void ChartExport::exportPlotArea( )
1180 Reference
< chart2::XCoordinateSystemContainer
> xBCooSysCnt( mxNewDiagram
, uno::UNO_QUERY
);
1181 if( ! xBCooSysCnt
.is())
1184 // plot-area element
1186 FSHelperPtr pFS
= GetFS();
1187 pFS
->startElement( FSNS( XML_c
, XML_plotArea
),
1190 Reference
<beans::XPropertySet
> xWall(mxNewDiagram
, uno::UNO_QUERY
);
1193 uno::Any aAny
= xWall
->getPropertyValue("RelativePosition");
1194 if (aAny
.hasValue())
1196 chart2::RelativePosition aPos
= aAny
.get
<chart2::RelativePosition
>();
1197 aAny
= xWall
->getPropertyValue("RelativeSize");
1198 chart2::RelativeSize aSize
= aAny
.get
<chart2::RelativeSize
>();
1199 exportManualLayout(aPos
, aSize
);
1204 Sequence
< Reference
< chart2::XCoordinateSystem
> >
1205 aCooSysSeq( xBCooSysCnt
->getCoordinateSystems());
1206 for( sal_Int32 nCSIdx
=0; nCSIdx
<aCooSysSeq
.getLength(); ++nCSIdx
)
1209 Reference
< chart2::XChartTypeContainer
> xCTCnt( aCooSysSeq
[nCSIdx
], uno::UNO_QUERY
);
1213 Sequence
< Reference
< chart2::XChartType
> > aCTSeq( xCTCnt
->getChartTypes());
1214 for( sal_Int32 nCTIdx
=0; nCTIdx
<aCTSeq
.getLength(); ++nCTIdx
)
1216 Reference
< chart2::XDataSeriesContainer
> xDSCnt( aCTSeq
[nCTIdx
], uno::UNO_QUERY
);
1219 Reference
< chart2::XChartType
> xChartType( aCTSeq
[nCTIdx
], uno::UNO_QUERY
);
1220 if( ! xChartType
.is())
1222 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
1223 OUString
aChartType( xChartType
->getChartType());
1224 sal_Int32 eChartType
= lcl_getChartType( aChartType
);
1225 switch( eChartType
)
1227 case chart::TYPEID_BAR
:
1229 exportBarChart( xChartType
);
1232 case chart::TYPEID_AREA
:
1234 exportAreaChart( xChartType
);
1237 case chart::TYPEID_LINE
:
1239 exportLineChart( xChartType
);
1242 case chart::TYPEID_BUBBLE
:
1244 exportBubbleChart( xChartType
);
1247 case chart::TYPEID_OFPIE
:
1251 case chart::TYPEID_DOUGHNUT
:
1252 case chart::TYPEID_PIE
:
1254 exportPieChart( xChartType
);
1257 case chart::TYPEID_RADARLINE
:
1258 case chart::TYPEID_RADARAREA
:
1260 exportRadarChart( xChartType
);
1263 case chart::TYPEID_SCATTER
:
1265 exportScatterChart( xChartType
);
1268 case chart::TYPEID_STOCK
:
1270 exportStockChart( xChartType
);
1273 case chart::TYPEID_SURFACE
:
1275 exportSurfaceChart( xChartType
);
1280 SAL_WARN("oox", "ChartExport::exportPlotArea -- not support chart type");
1294 * Export the Plot area Shape Properties
1295 * eg: Fill and Outline
1297 Reference
< css::chart::X3DDisplay
> xWallFloorSupplier( mxDiagram
, uno::UNO_QUERY
);
1298 if( xWallFloorSupplier
.is() )
1300 Reference
< beans::XPropertySet
> xWallPropSet( xWallFloorSupplier
->getWall(), uno::UNO_QUERY
);
1301 if( xWallPropSet
.is() )
1303 exportPlotAreaShapeProps( xWallPropSet
);
1307 pFS
->endElement( FSNS( XML_c
, XML_plotArea
) );
1311 void ChartExport::exportManualLayout(const css::chart2::RelativePosition
& rPos
, const css::chart2::RelativeSize
& rSize
)
1313 FSHelperPtr pFS
= GetFS();
1314 pFS
->startElement(FSNS(XML_c
, XML_layout
), FSEND
);
1315 pFS
->startElement(FSNS(XML_c
, XML_manualLayout
), FSEND
);
1316 pFS
->singleElement(FSNS(XML_c
, XML_layoutTarget
),
1319 pFS
->singleElement(FSNS(XML_c
, XML_xMode
),
1322 pFS
->singleElement(FSNS(XML_c
, XML_yMode
),
1326 double x
= rPos
.Primary
;
1327 double y
= rPos
.Secondary
;
1328 double w
= rSize
.Primary
;
1329 double h
= rSize
.Secondary
;
1330 switch (rPos
.Anchor
)
1332 case drawing::Alignment_LEFT
:
1335 case drawing::Alignment_TOP_LEFT
:
1337 case drawing::Alignment_BOTTOM_LEFT
:
1340 case drawing::Alignment_TOP
:
1343 case drawing::Alignment_CENTER
:
1347 case drawing::Alignment_BOTTOM
:
1351 case drawing::Alignment_TOP_RIGHT
:
1354 case drawing::Alignment_BOTTOM_RIGHT
:
1358 case drawing::Alignment_RIGHT
:
1363 SAL_WARN("oox", "unhandled alignment case for manual layout export");
1366 pFS
->singleElement(FSNS(XML_c
, XML_x
),
1370 pFS
->singleElement(FSNS(XML_c
, XML_y
),
1374 pFS
->singleElement(FSNS(XML_c
, XML_w
),
1378 pFS
->singleElement(FSNS(XML_c
, XML_h
),
1382 pFS
->endElement(FSNS(XML_c
, XML_manualLayout
));
1383 pFS
->endElement(FSNS(XML_c
, XML_layout
));
1386 void ChartExport::exportPlotAreaShapeProps( const Reference
< XPropertySet
>& xPropSet
)
1388 FSHelperPtr pFS
= GetFS();
1389 pFS
->startElement( FSNS( XML_c
, XML_spPr
),
1392 exportFill( xPropSet
);
1393 WriteOutline( xPropSet
);
1395 pFS
->endElement( FSNS( XML_c
, XML_spPr
) );
1398 void ChartExport::exportFill( const Reference
< XPropertySet
>& xPropSet
)
1400 if ( !GetProperty( xPropSet
, "FillStyle" ) )
1402 FillStyle
aFillStyle( FillStyle_NONE
);
1403 xPropSet
->getPropertyValue( "FillStyle" ) >>= aFillStyle
;
1404 switch( aFillStyle
)
1406 case FillStyle_GRADIENT
:
1407 exportGradientFill( xPropSet
);
1409 case FillStyle_BITMAP
:
1410 exportBitmapFill( xPropSet
);
1413 WriteFill( xPropSet
);
1417 void ChartExport::exportBitmapFill( const Reference
< XPropertySet
>& xPropSet
)
1421 OUString sFillBitmapName
;
1422 xPropSet
->getPropertyValue("FillBitmapName") >>= sFillBitmapName
;
1424 uno::Reference
< lang::XMultiServiceFactory
> xFact( getModel(), uno::UNO_QUERY
);
1427 uno::Reference
< container::XNameAccess
> xBitmap( xFact
->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY
);
1428 uno::Any rValue
= xBitmap
->getByName( sFillBitmapName
);
1429 OUString sBitmapURL
;
1430 if( (rValue
>>= sBitmapURL
) )
1432 WriteBlipFill( xPropSet
, sBitmapURL
, XML_a
, true, true );
1435 catch (const uno::Exception
& rEx
)
1437 SAL_INFO("oox", "ChartExport::exportBitmapFill " << rEx
.Message
);
1443 void ChartExport::exportGradientFill( const Reference
< XPropertySet
>& xPropSet
)
1447 OUString sFillGradientName
;
1448 xPropSet
->getPropertyValue("FillGradientName") >>= sFillGradientName
;
1450 awt::Gradient aGradient
;
1451 uno::Reference
< lang::XMultiServiceFactory
> xFact( getModel(), uno::UNO_QUERY
);
1454 uno::Reference
< container::XNameAccess
> xGradient( xFact
->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY
);
1455 uno::Any rValue
= xGradient
->getByName( sFillGradientName
);
1456 if( (rValue
>>= aGradient
) )
1458 mpFS
->startElementNS( XML_a
, XML_gradFill
, FSEND
);
1459 WriteGradientFill( aGradient
);
1460 mpFS
->endElementNS( XML_a
, XML_gradFill
);
1463 catch (const uno::Exception
& rEx
)
1466 "ChartExport::exportGradientFill " << rEx
.Message
);
1472 void ChartExport::exportDataTable( )
1474 FSHelperPtr pFS
= GetFS();
1475 Reference
< beans::XPropertySet
> aPropSet( mxDiagram
, uno::UNO_QUERY
);
1477 bool bShowVBorder
= false;
1478 bool bShowHBorder
= false;
1479 bool bShowOutline
= false;
1481 if (GetProperty( aPropSet
, "DataTableHBorder"))
1482 mAny
>>= bShowHBorder
;
1483 if (GetProperty( aPropSet
, "DataTableVBorder"))
1484 mAny
>>= bShowVBorder
;
1485 if (GetProperty( aPropSet
, "DataTableOutline"))
1486 mAny
>>= bShowOutline
;
1488 if (bShowVBorder
|| bShowHBorder
|| bShowOutline
)
1490 pFS
->startElement( FSNS( XML_c
, XML_dTable
),
1493 pFS
->singleElement( FSNS( XML_c
, XML_showHorzBorder
),
1497 pFS
->singleElement( FSNS( XML_c
, XML_showVertBorder
),
1501 pFS
->singleElement( FSNS( XML_c
, XML_showOutline
),
1505 pFS
->endElement( FSNS( XML_c
, XML_dTable
));
1509 void ChartExport::exportAreaChart( const Reference
< chart2::XChartType
>& xChartType
)
1511 FSHelperPtr pFS
= GetFS();
1512 sal_Int32 nTypeId
= XML_areaChart
;
1514 nTypeId
= XML_area3DChart
;
1515 pFS
->startElement( FSNS( XML_c
, nTypeId
),
1519 bool bPrimaryAxes
= true;
1520 exportAllSeries(xChartType
, bPrimaryAxes
);
1521 exportAxesId(bPrimaryAxes
);
1523 pFS
->endElement( FSNS( XML_c
, nTypeId
) );
1526 void ChartExport::exportBarChart( const Reference
< chart2::XChartType
>& xChartType
)
1528 sal_Int32 nTypeId
= XML_barChart
;
1530 nTypeId
= XML_bar3DChart
;
1531 FSHelperPtr pFS
= GetFS();
1532 pFS
->startElement( FSNS( XML_c
, nTypeId
),
1535 bool bVertical
= false;
1536 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
1537 if( GetProperty( xPropSet
, "Vertical" ) )
1540 const char* bardir
= bVertical
? "bar":"col";
1541 pFS
->singleElement( FSNS( XML_c
, XML_barDir
),
1545 exportGrouping( true );
1547 exportVaryColors(xChartType
);
1549 bool bPrimaryAxes
= true;
1550 exportAllSeries(xChartType
, bPrimaryAxes
);
1552 Reference
< XPropertySet
> xTypeProp( xChartType
, uno::UNO_QUERY
);
1554 if( xTypeProp
.is() && GetProperty( xTypeProp
, "GapwidthSequence") )
1556 uno::Sequence
< sal_Int32
> aBarPositionSequence
;
1557 mAny
>>= aBarPositionSequence
;
1558 if( aBarPositionSequence
.getLength() )
1560 sal_Int32 nGapWidth
= aBarPositionSequence
[0];
1561 pFS
->singleElement( FSNS( XML_c
, XML_gapWidth
),
1562 XML_val
, I32S( nGapWidth
),
1570 namespace cssc
= css::chart
;
1571 sal_Int32 nGeom3d
= cssc::ChartSolidType::RECTANGULAR_SOLID
;
1572 if( xPropSet
.is() && GetProperty( xPropSet
, "SolidType") )
1574 const char* sShapeType
= nullptr;
1577 case cssc::ChartSolidType::RECTANGULAR_SOLID
:
1580 case cssc::ChartSolidType::CONE
:
1581 sShapeType
= "cone";
1583 case cssc::ChartSolidType::CYLINDER
:
1584 sShapeType
= "cylinder";
1586 case cssc::ChartSolidType::PYRAMID
:
1587 sShapeType
= "pyramid";
1590 pFS
->singleElement( FSNS( XML_c
, XML_shape
),
1591 XML_val
, sShapeType
,
1596 if( !mbIs3DChart
&& xTypeProp
.is() && GetProperty( xTypeProp
, "OverlapSequence") )
1598 uno::Sequence
< sal_Int32
> aBarPositionSequence
;
1599 mAny
>>= aBarPositionSequence
;
1600 if( aBarPositionSequence
.getLength() )
1602 sal_Int32 nOverlap
= aBarPositionSequence
[0];
1603 pFS
->singleElement( FSNS( XML_c
, XML_overlap
),
1604 XML_val
, I32S( nOverlap
),
1609 exportAxesId(bPrimaryAxes
);
1611 pFS
->endElement( FSNS( XML_c
, nTypeId
) );
1614 void ChartExport::exportBubbleChart( const Reference
< chart2::XChartType
>& xChartType
)
1616 FSHelperPtr pFS
= GetFS();
1617 pFS
->startElement( FSNS( XML_c
, XML_bubbleChart
),
1620 exportVaryColors(xChartType
);
1622 bool bPrimaryAxes
= true;
1623 exportAllSeries(xChartType
, bPrimaryAxes
);
1625 pFS
->singleElement(FSNS(XML_c
, XML_bubble3D
),
1629 exportAxesId(bPrimaryAxes
);
1631 pFS
->endElement( FSNS( XML_c
, XML_bubbleChart
) );
1634 void ChartExport::exportDoughnutChart( const Reference
< chart2::XChartType
>& xChartType
)
1636 FSHelperPtr pFS
= GetFS();
1637 pFS
->startElement( FSNS( XML_c
, XML_doughnutChart
),
1640 exportVaryColors(xChartType
);
1642 bool bPrimaryAxes
= true;
1643 exportAllSeries(xChartType
, bPrimaryAxes
);
1645 exportFirstSliceAng( );
1647 sal_Int32 nHoleSize
= 50;
1648 pFS
->singleElement( FSNS( XML_c
, XML_holeSize
),
1649 XML_val
, I32S( nHoleSize
),
1652 pFS
->endElement( FSNS( XML_c
, XML_doughnutChart
) );
1657 std::vector
<Sequence
<Reference
<chart2::XDataSeries
> > > splitDataSeriesByAxis(const Reference
< chart2::XChartType
>& xChartType
)
1659 std::vector
<Sequence
<Reference
<chart2::XDataSeries
> > > aSplitSeries
;
1660 std::map
<sal_Int32
, size_t> aMapAxisToIndex
;
1662 Reference
< chart2::XDataSeriesContainer
> xDSCnt( xChartType
, uno::UNO_QUERY
);
1665 Sequence
< Reference
< chart2::XDataSeries
> > aSeriesSeq( xDSCnt
->getDataSeries());
1666 for (sal_Int32 nIndex
= 0, nEnd
= aSeriesSeq
.getLength(); nIndex
< nEnd
; ++nIndex
)
1668 uno::Reference
<chart2::XDataSeries
> xSeries
= aSeriesSeq
[nIndex
];
1669 Reference
<beans::XPropertySet
> xPropSet(xSeries
, uno::UNO_QUERY
);
1673 sal_Int32 nAxisIndex
= -1;
1674 uno::Any aAny
= xPropSet
->getPropertyValue("AttachedAxisIndex");
1675 aAny
>>= nAxisIndex
;
1676 size_t nVectorPos
= 0;
1678 auto it
= aMapAxisToIndex
.find(nAxisIndex
);
1679 if (it
== aMapAxisToIndex
.end())
1681 aSplitSeries
.push_back(Sequence
<Reference
<chart2::XDataSeries
> >());
1682 nVectorPos
= aSplitSeries
.size() - 1;
1683 aMapAxisToIndex
.insert(std::pair
<sal_Int32
, size_t>(nAxisIndex
, nVectorPos
));
1686 uno::Sequence
<Reference
<chart2::XDataSeries
> >& rAxisSeriesSeq
= aSplitSeries
[nVectorPos
];
1687 sal_Int32 nLength
= rAxisSeriesSeq
.getLength();
1688 rAxisSeriesSeq
.realloc(nLength
+ 1);
1689 rAxisSeriesSeq
[nLength
] = xSeries
;
1693 return aSplitSeries
;
1698 void ChartExport::exportLineChart( const Reference
< chart2::XChartType
>& xChartType
)
1700 FSHelperPtr pFS
= GetFS();
1701 std::vector
<Sequence
<Reference
<chart2::XDataSeries
> > > aSplitDataSeries
= splitDataSeriesByAxis(xChartType
);
1702 for (auto itr
= aSplitDataSeries
.begin(), itrEnd
= aSplitDataSeries
.end();
1703 itr
!= itrEnd
; ++itr
)
1705 if (itr
->getLength() == 0)
1708 sal_Int32 nTypeId
= XML_lineChart
;
1710 nTypeId
= XML_line3DChart
;
1711 pFS
->startElement( FSNS( XML_c
, nTypeId
),
1714 exportVaryColors(xChartType
);
1717 // TODO: show marker symbol in series?
1718 bool bPrimaryAxes
= true;
1719 exportSeries(xChartType
, *itr
, bPrimaryAxes
);
1722 sal_Int32 nSymbolType
= css::chart::ChartSymbolType::NONE
;
1723 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
1724 if( GetProperty( xPropSet
, "SymbolType" ) )
1725 mAny
>>= nSymbolType
;
1730 exportUpDownBars(xChartType
);
1731 const char* marker
= nSymbolType
== css::chart::ChartSymbolType::NONE
? "0":"1";
1732 pFS
->singleElement( FSNS( XML_c
, XML_marker
),
1737 exportAxesId(bPrimaryAxes
);
1739 pFS
->endElement( FSNS( XML_c
, nTypeId
) );
1743 void ChartExport::exportPieChart( const Reference
< chart2::XChartType
>& xChartType
)
1745 sal_Int32 eChartType
= getChartType( );
1746 if(eChartType
== chart::TYPEID_DOUGHNUT
)
1748 exportDoughnutChart( xChartType
);
1751 FSHelperPtr pFS
= GetFS();
1752 sal_Int32 nTypeId
= XML_pieChart
;
1754 nTypeId
= XML_pie3DChart
;
1755 pFS
->startElement( FSNS( XML_c
, nTypeId
),
1758 exportVaryColors(xChartType
);
1760 bool bPrimaryAxes
= true;
1761 exportAllSeries(xChartType
, bPrimaryAxes
);
1766 exportFirstSliceAng( );
1769 pFS
->endElement( FSNS( XML_c
, nTypeId
) );
1772 void ChartExport::exportRadarChart( const Reference
< chart2::XChartType
>& xChartType
)
1774 FSHelperPtr pFS
= GetFS();
1775 pFS
->startElement( FSNS( XML_c
, XML_radarChart
),
1779 sal_Int32 eChartType
= getChartType( );
1780 const char* radarStyle
= nullptr;
1781 if( eChartType
== chart::TYPEID_RADARAREA
)
1782 radarStyle
= "filled";
1784 radarStyle
= "marker";
1785 pFS
->singleElement( FSNS( XML_c
, XML_radarStyle
),
1786 XML_val
, radarStyle
,
1789 exportVaryColors(xChartType
);
1790 bool bPrimaryAxes
= true;
1791 exportAllSeries(xChartType
, bPrimaryAxes
);
1792 exportAxesId(bPrimaryAxes
);
1794 pFS
->endElement( FSNS( XML_c
, XML_radarChart
) );
1797 void ChartExport::exportScatterChart( const Reference
< chart2::XChartType
>& xChartType
)
1799 FSHelperPtr pFS
= GetFS();
1800 std::vector
<Sequence
<Reference
<chart2::XDataSeries
> > > aSplitDataSeries
= splitDataSeriesByAxis(xChartType
);
1801 for (auto itr
= aSplitDataSeries
.begin(), itrEnd
= aSplitDataSeries
.end();
1802 itr
!= itrEnd
; ++itr
)
1804 if (itr
->getLength() == 0)
1807 pFS
->startElement( FSNS( XML_c
, XML_scatterChart
),
1809 // TODO:scatterStyle
1811 sal_Int32 nSymbolType
= css::chart::ChartSymbolType::NONE
;
1812 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
1813 if( GetProperty( xPropSet
, "SymbolType" ) )
1814 mAny
>>= nSymbolType
;
1816 const char* scatterStyle
= "lineMarker";
1817 if (nSymbolType
== css::chart::ChartSymbolType::NONE
)
1819 scatterStyle
= "line";
1822 pFS
->singleElement( FSNS( XML_c
, XML_scatterStyle
),
1823 XML_val
, scatterStyle
,
1826 exportVaryColors(xChartType
);
1827 // FIXME: should export xVal and yVal
1828 bool bPrimaryAxes
= true;
1829 exportSeries(xChartType
, *itr
, bPrimaryAxes
);
1830 exportAxesId(bPrimaryAxes
);
1832 pFS
->endElement( FSNS( XML_c
, XML_scatterChart
) );
1836 void ChartExport::exportStockChart( const Reference
< chart2::XChartType
>& xChartType
)
1838 FSHelperPtr pFS
= GetFS();
1839 pFS
->startElement( FSNS( XML_c
, XML_stockChart
),
1842 bool bPrimaryAxes
= true;
1843 Reference
< chart2::XDataSeriesContainer
> xDSCnt( xChartType
, uno::UNO_QUERY
);
1845 exportCandleStickSeries( xDSCnt
->getDataSeries(), bPrimaryAxes
);
1847 // export stock properties
1848 Reference
< css::chart::XStatisticDisplay
> xStockPropProvider( mxDiagram
, uno::UNO_QUERY
);
1849 if( xStockPropProvider
.is())
1852 exportUpDownBars(xChartType
);
1855 exportAxesId(bPrimaryAxes
);
1857 pFS
->endElement( FSNS( XML_c
, XML_stockChart
) );
1860 void ChartExport::exportHiLowLines()
1862 FSHelperPtr pFS
= GetFS();
1863 // export the chart property
1864 Reference
< css::chart::XStatisticDisplay
> xChartPropProvider( mxDiagram
, uno::UNO_QUERY
);
1866 if (!xChartPropProvider
.is())
1869 Reference
< beans::XPropertySet
> xStockPropSet
= xChartPropProvider
->getMinMaxLine();
1870 if( !xStockPropSet
.is() )
1873 pFS
->startElement( FSNS( XML_c
, XML_hiLowLines
),
1875 exportShapeProps( xStockPropSet
);
1876 pFS
->endElement( FSNS( XML_c
, XML_hiLowLines
) );
1879 void ChartExport::exportUpDownBars( const Reference
< chart2::XChartType
>& xChartType
)
1881 if(xChartType
->getChartType() != "com.sun.star.chart2.CandleStickChartType")
1884 FSHelperPtr pFS
= GetFS();
1885 // export the chart property
1886 Reference
< css::chart::XStatisticDisplay
> xChartPropProvider( mxDiagram
, uno::UNO_QUERY
);
1887 if(xChartPropProvider
.is())
1890 pFS
->startElement( FSNS( XML_c
, XML_upDownBars
),
1893 sal_Int32 nGapWidth
= 150;
1894 pFS
->singleElement( FSNS( XML_c
, XML_gapWidth
),
1895 XML_val
, I32S( nGapWidth
),
1898 Reference
< beans::XPropertySet
> xChartPropSet
= xChartPropProvider
->getUpBar();
1899 if( xChartPropSet
.is() )
1901 pFS
->startElement( FSNS( XML_c
, XML_upBars
),
1903 // For Linechart with UpDownBars, spPr is not getting imported
1904 // so no need to call the exportShapeProps() for LineChart
1905 if(xChartType
->getChartType() == "com.sun.star.chart2.CandleStickChartType")
1907 exportShapeProps(xChartPropSet
);
1909 pFS
->endElement( FSNS( XML_c
, XML_upBars
) );
1911 xChartPropSet
= xChartPropProvider
->getDownBar();
1912 if( xChartPropSet
.is() )
1914 pFS
->startElement( FSNS( XML_c
, XML_downBars
),
1916 if(xChartType
->getChartType() == "com.sun.star.chart2.CandleStickChartType")
1918 exportShapeProps(xChartPropSet
);
1920 pFS
->endElement( FSNS( XML_c
, XML_downBars
) );
1922 pFS
->endElement( FSNS( XML_c
, XML_upDownBars
) );
1926 void ChartExport::exportSurfaceChart( const Reference
< chart2::XChartType
>& xChartType
)
1928 FSHelperPtr pFS
= GetFS();
1929 sal_Int32 nTypeId
= XML_surfaceChart
;
1931 nTypeId
= XML_surface3DChart
;
1932 pFS
->startElement( FSNS( XML_c
, nTypeId
),
1934 exportVaryColors(xChartType
);
1935 bool bPrimaryAxes
= true;
1936 exportAllSeries(xChartType
, bPrimaryAxes
);
1937 exportAxesId(bPrimaryAxes
);
1939 pFS
->endElement( FSNS( XML_c
, nTypeId
) );
1942 void ChartExport::exportAllSeries(const Reference
<chart2::XChartType
>& xChartType
, bool& rPrimaryAxes
)
1944 Reference
< chart2::XDataSeriesContainer
> xDSCnt( xChartType
, uno::UNO_QUERY
);
1948 // export dataseries for current chart-type
1949 Sequence
< Reference
< chart2::XDataSeries
> > aSeriesSeq( xDSCnt
->getDataSeries());
1950 exportSeries(xChartType
, aSeriesSeq
, rPrimaryAxes
);
1955 Reference
<chart2::XDataSeries
> getPrimaryDataSeries(const Reference
<chart2::XChartType
>& xChartType
)
1957 Reference
< chart2::XDataSeriesContainer
> xDSCnt(xChartType
, uno::UNO_QUERY_THROW
);
1959 // export dataseries for current chart-type
1960 Sequence
< Reference
< chart2::XDataSeries
> > aSeriesSeq(xDSCnt
->getDataSeries());
1961 for (sal_Int32 nSeriesIdx
=0; nSeriesIdx
< aSeriesSeq
.getLength(); ++nSeriesIdx
)
1963 Reference
<chart2::XDataSeries
> xSource(aSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
);
1968 return Reference
<chart2::XDataSeries
>();
1973 void ChartExport::exportVaryColors(const Reference
<chart2::XChartType
>& xChartType
)
1975 FSHelperPtr pFS
= GetFS();
1978 Reference
<chart2::XDataSeries
> xDataSeries
= getPrimaryDataSeries(xChartType
);
1979 Reference
<beans::XPropertySet
> xDataSeriesProps(xDataSeries
, uno::UNO_QUERY_THROW
);
1980 Any aAnyVaryColors
= xDataSeriesProps
->getPropertyValue("VaryColorsByPoint");
1981 bool bVaryColors
= false;
1982 aAnyVaryColors
>>= bVaryColors
;
1983 pFS
->singleElement(FSNS(XML_c
, XML_varyColors
),
1984 XML_val
, bVaryColors
? "1": "0",
1989 pFS
->singleElement(FSNS(XML_c
, XML_varyColors
),
1995 void ChartExport::exportSeries( const Reference
<chart2::XChartType
>& xChartType
,
1996 Sequence
<Reference
<chart2::XDataSeries
> >& rSeriesSeq
, bool& rPrimaryAxes
)
1998 OUString aLabelRole
= xChartType
->getRoleOfSequenceForSeriesLabel();
1999 OUString
aChartType( xChartType
->getChartType());
2000 sal_Int32 eChartType
= lcl_getChartType( aChartType
);
2002 for( sal_Int32 nSeriesIdx
=0; nSeriesIdx
<rSeriesSeq
.getLength(); ++nSeriesIdx
)
2005 Reference
< chart2::data::XDataSource
> xSource( rSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
);
2008 Reference
< chart2::XDataSeries
> xDataSeries( xSource
, uno::UNO_QUERY
);
2009 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
2010 xSource
->getDataSequences());
2011 // search for main sequence and create a series element
2013 sal_Int32 nMainSequenceIndex
= -1;
2014 sal_Int32 nSeriesLength
= 0;
2015 Reference
< chart2::data::XDataSequence
> xValuesSeq
;
2016 Reference
< chart2::data::XDataSequence
> xLabelSeq
;
2017 sal_Int32 nSeqIdx
=0;
2018 for( ; nSeqIdx
<aSeqCnt
.getLength(); ++nSeqIdx
)
2021 Reference
< chart2::data::XDataSequence
> xTempValueSeq( aSeqCnt
[nSeqIdx
]->getValues() );
2022 if( nMainSequenceIndex
==-1 )
2024 Reference
< beans::XPropertySet
> xSeqProp( xTempValueSeq
, uno::UNO_QUERY
);
2026 xSeqProp
->getPropertyValue("Role") >>= aRole
;
2028 if( aRole
.equals( aLabelRole
))
2030 xValuesSeq
.set( xTempValueSeq
);
2031 xLabelSeq
.set( aSeqCnt
[nSeqIdx
]->getLabel());
2032 nMainSequenceIndex
= nSeqIdx
;
2035 sal_Int32 nSequenceLength
= (xTempValueSeq
.is()? xTempValueSeq
->getData().getLength() : sal_Int32(0));
2036 if( nSeriesLength
< nSequenceLength
)
2037 nSeriesLength
= nSequenceLength
;
2040 // have found the main sequence, then xValuesSeq and
2041 // xLabelSeq contain those. Otherwise both are empty
2043 FSHelperPtr pFS
= GetFS();
2045 pFS
->startElement( FSNS( XML_c
, XML_ser
),
2048 // TODO: idx and order
2049 pFS
->singleElement( FSNS( XML_c
, XML_idx
),
2050 XML_val
, I32S(mnSeriesCount
),
2052 pFS
->singleElement( FSNS( XML_c
, XML_order
),
2053 XML_val
, I32S(mnSeriesCount
++),
2057 if( xLabelSeq
.is() )
2058 exportSeriesText( xLabelSeq
);
2060 Reference
<XPropertySet
> xPropSet(xDataSeries
, UNO_QUERY_THROW
);
2061 if( GetProperty( xPropSet
, "AttachedAxisIndex") )
2063 sal_Int32 nLocalAttachedAxis
= 0;
2064 mAny
>>= nLocalAttachedAxis
;
2065 rPrimaryAxes
= isPrimaryAxes(nLocalAttachedAxis
);
2068 // export shape properties
2069 Reference
< XPropertySet
> xOldPropSet
= SchXMLSeriesHelper::createOldAPISeriesPropertySet(
2070 rSeriesSeq
[nSeriesIdx
], getModel() );
2071 if( xOldPropSet
.is() )
2073 exportShapeProps( xOldPropSet
);
2076 switch( eChartType
)
2078 case chart::TYPEID_BUBBLE
:
2079 case chart::TYPEID_HORBAR
:
2080 case chart::TYPEID_BAR
:
2082 pFS
->singleElement(FSNS(XML_c
, XML_invertIfNegative
),
2087 case chart::TYPEID_LINE
:
2089 exportMarker(xDataSeries
);
2092 case chart::TYPEID_PIE
:
2093 case chart::TYPEID_DOUGHNUT
:
2095 if( xOldPropSet
.is() && GetProperty( xOldPropSet
, "SegmentOffset") )
2097 sal_Int32 nOffset
= 0;
2099 pFS
->singleElement( FSNS( XML_c
, XML_explosion
),
2100 XML_val
, I32S( nOffset
),
2105 case chart::TYPEID_SCATTER
:
2107 exportMarker(xDataSeries
);
2110 case chart::TYPEID_RADARLINE
:
2112 exportMarker(xDataSeries
);
2117 // export data points
2118 exportDataPoints( uno::Reference
< beans::XPropertySet
>( rSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
), nSeriesLength
);
2120 // export data labels
2121 exportDataLabels(rSeriesSeq
[nSeriesIdx
], nSeriesLength
, eChartType
);
2123 exportTrendlines( rSeriesSeq
[nSeriesIdx
] );
2125 if( eChartType
!= chart::TYPEID_PIE
&&
2126 eChartType
!= chart::TYPEID_RADARLINE
)
2128 //export error bars here
2129 Reference
< XPropertySet
> xSeriesPropSet( xSource
, uno::UNO_QUERY
);
2130 Reference
< XPropertySet
> xErrorBarYProps
;
2131 xSeriesPropSet
->getPropertyValue("ErrorBarY") >>= xErrorBarYProps
;
2132 if(xErrorBarYProps
.is())
2133 exportErrorBar(xErrorBarYProps
, true);
2134 if (eChartType
!= chart::TYPEID_BAR
&&
2135 eChartType
!= chart::TYPEID_HORBAR
)
2137 Reference
< XPropertySet
> xErrorBarXProps
;
2138 xSeriesPropSet
->getPropertyValue("ErrorBarX") >>= xErrorBarXProps
;
2139 if(xErrorBarXProps
.is())
2140 exportErrorBar(xErrorBarXProps
, false);
2144 // export categories
2145 if( eChartType
!= chart::TYPEID_SCATTER
&& mxCategoriesValues
.is() )
2146 exportSeriesCategory( mxCategoriesValues
);
2148 if( (eChartType
== chart::TYPEID_SCATTER
)
2149 || (eChartType
== chart::TYPEID_BUBBLE
) )
2152 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, "values-x" ) );
2153 if( xSequence
.is() )
2155 Reference
< chart2::data::XDataSequence
> xValues( xSequence
->getValues() );
2157 exportSeriesValues( xValues
, XML_xVal
);
2161 if( eChartType
== chart::TYPEID_BUBBLE
)
2164 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, "values-y" ) );
2165 if( xSequence
.is() )
2167 Reference
< chart2::data::XDataSequence
> xValues( xSequence
->getValues() );
2169 exportSeriesValues( xValues
, XML_yVal
);
2174 if( xValuesSeq
.is() )
2176 sal_Int32 nYValueType
= XML_val
;
2177 if( eChartType
== chart::TYPEID_SCATTER
)
2178 nYValueType
= XML_yVal
;
2179 else if( eChartType
== chart::TYPEID_BUBBLE
)
2180 nYValueType
= XML_bubbleSize
;
2181 exportSeriesValues( xValuesSeq
, nYValueType
);
2184 if( eChartType
== chart::TYPEID_SCATTER
2185 || eChartType
== chart::TYPEID_LINE
)
2188 pFS
->endElement( FSNS( XML_c
, XML_ser
) );
2195 void ChartExport::exportCandleStickSeries(
2196 const Sequence
< Reference
< chart2::XDataSeries
> > & aSeriesSeq
,
2199 for( sal_Int32 nSeriesIdx
=0; nSeriesIdx
<aSeriesSeq
.getLength(); ++nSeriesIdx
)
2201 Reference
< chart2::XDataSeries
> xSeries( aSeriesSeq
[nSeriesIdx
] );
2202 rPrimaryAxes
= lcl_isSeriesAttachedToFirstAxis(xSeries
);
2204 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
2207 // export series in correct order (as we don't store roles)
2208 // with japanese candlesticks: open, low, high, close
2209 // otherwise: low, high, close
2210 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
2211 xSource
->getDataSequences());
2213 const char* sSeries
[] = {"values-first","values-max","values-min","values-last",nullptr};
2215 for( sal_Int32 idx
= 0; sSeries
[idx
] != nullptr ; idx
++ )
2217 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq( lcl_getDataSequenceByRole( aSeqCnt
, OUString::createFromAscii(sSeries
[idx
]) ) );
2218 if( xLabeledSeq
.is())
2220 Reference
< chart2::data::XDataSequence
> xLabelSeq( xLabeledSeq
->getLabel());
2221 Reference
< chart2::data::XDataSequence
> xValueSeq( xLabeledSeq
->getValues());
2223 FSHelperPtr pFS
= GetFS();
2224 pFS
->startElement( FSNS( XML_c
, XML_ser
),
2227 // TODO: idx and order
2228 // idx attribute should start from 1 and not from 0.
2229 pFS
->singleElement( FSNS( XML_c
, XML_idx
),
2230 XML_val
, I32S(idx
+1),
2232 pFS
->singleElement( FSNS( XML_c
, XML_order
),
2233 XML_val
, I32S(idx
+1),
2237 if( xLabelSeq
.is() )
2238 exportSeriesText( xLabelSeq
);
2240 // TODO:export shape properties
2242 // export categories
2243 if( mxCategoriesValues
.is() )
2244 exportSeriesCategory( mxCategoriesValues
);
2247 if( xValueSeq
.is() )
2248 exportSeriesValues( xValueSeq
);
2250 pFS
->endElement( FSNS( XML_c
, XML_ser
) );
2258 void ChartExport::exportSeriesText( const Reference
< chart2::data::XDataSequence
> & xValueSeq
)
2260 FSHelperPtr pFS
= GetFS();
2261 pFS
->startElement( FSNS( XML_c
, XML_tx
),
2264 OUString aCellRange
= xValueSeq
->getSourceRangeRepresentation();
2265 aCellRange
= parseFormula( aCellRange
);
2266 pFS
->startElement( FSNS( XML_c
, XML_strRef
),
2269 pFS
->startElement( FSNS( XML_c
, XML_f
),
2271 pFS
->writeEscaped( aCellRange
);
2272 pFS
->endElement( FSNS( XML_c
, XML_f
) );
2274 OUString aLabelString
= lcl_getLabelString( xValueSeq
);
2275 pFS
->startElement( FSNS( XML_c
, XML_strCache
),
2277 pFS
->singleElement( FSNS( XML_c
, XML_ptCount
),
2280 pFS
->startElement( FSNS( XML_c
, XML_pt
),
2283 pFS
->startElement( FSNS( XML_c
, XML_v
),
2285 pFS
->writeEscaped( aLabelString
);
2286 pFS
->endElement( FSNS( XML_c
, XML_v
) );
2287 pFS
->endElement( FSNS( XML_c
, XML_pt
) );
2288 pFS
->endElement( FSNS( XML_c
, XML_strCache
) );
2289 pFS
->endElement( FSNS( XML_c
, XML_strRef
) );
2290 pFS
->endElement( FSNS( XML_c
, XML_tx
) );
2293 void ChartExport::exportSeriesCategory( const Reference
< chart2::data::XDataSequence
> & xValueSeq
)
2295 FSHelperPtr pFS
= GetFS();
2296 pFS
->startElement( FSNS( XML_c
, XML_cat
),
2299 OUString aCellRange
= xValueSeq
.is() ? xValueSeq
->getSourceRangeRepresentation() : OUString();
2300 aCellRange
= parseFormula( aCellRange
);
2301 // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2302 pFS
->startElement( FSNS( XML_c
, XML_strRef
),
2305 pFS
->startElement( FSNS( XML_c
, XML_f
),
2307 pFS
->writeEscaped( aCellRange
);
2308 pFS
->endElement( FSNS( XML_c
, XML_f
) );
2310 ::std::vector
< OUString
> aCategories
;
2311 lcl_fillCategoriesIntoStringVector( xValueSeq
, aCategories
);
2312 sal_Int32 ptCount
= aCategories
.size();
2313 pFS
->startElement( FSNS( XML_c
, XML_strCache
),
2315 pFS
->singleElement( FSNS( XML_c
, XML_ptCount
),
2316 XML_val
, I32S( ptCount
),
2318 for( sal_Int32 i
= 0; i
< ptCount
; i
++ )
2320 pFS
->startElement( FSNS( XML_c
, XML_pt
),
2323 pFS
->startElement( FSNS( XML_c
, XML_v
),
2325 pFS
->writeEscaped( aCategories
[i
] );
2326 pFS
->endElement( FSNS( XML_c
, XML_v
) );
2327 pFS
->endElement( FSNS( XML_c
, XML_pt
) );
2330 pFS
->endElement( FSNS( XML_c
, XML_strCache
) );
2331 pFS
->endElement( FSNS( XML_c
, XML_strRef
) );
2332 pFS
->endElement( FSNS( XML_c
, XML_cat
) );
2335 void ChartExport::exportSeriesValues( const Reference
< chart2::data::XDataSequence
> & xValueSeq
, sal_Int32 nValueType
)
2337 FSHelperPtr pFS
= GetFS();
2338 pFS
->startElement( FSNS( XML_c
, nValueType
),
2341 OUString aCellRange
= xValueSeq
.is() ? xValueSeq
->getSourceRangeRepresentation() : OUString();
2342 aCellRange
= parseFormula( aCellRange
);
2343 // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2344 pFS
->startElement( FSNS( XML_c
, XML_numRef
),
2347 pFS
->startElement( FSNS( XML_c
, XML_f
),
2349 pFS
->writeEscaped( aCellRange
);
2350 pFS
->endElement( FSNS( XML_c
, XML_f
) );
2352 ::std::vector
< double > aValues
;
2353 aValues
= lcl_getAllValuesFromSequence( xValueSeq
);
2354 sal_Int32 ptCount
= aValues
.size();
2355 pFS
->startElement( FSNS( XML_c
, XML_numCache
),
2357 pFS
->startElement( FSNS( XML_c
, XML_formatCode
),
2359 // TODO: what format code?
2360 pFS
->writeEscaped( "General" );
2361 pFS
->endElement( FSNS( XML_c
, XML_formatCode
) );
2362 pFS
->singleElement( FSNS( XML_c
, XML_ptCount
),
2363 XML_val
, I32S( ptCount
),
2366 bool bIsNumberValue
= true;
2367 bool bXSeriesValue
= false;
2370 if(nValueType
== XML_xVal
)
2371 bXSeriesValue
= true;
2373 for( sal_Int32 i
= 0; i
< ptCount
; i
++ )
2375 pFS
->startElement( FSNS( XML_c
, XML_pt
),
2378 pFS
->startElement( FSNS( XML_c
, XML_v
),
2380 if (bIsNumberValue
&& !rtl::math::isNan(aValues
[i
]))
2381 pFS
->write( aValues
[i
] );
2382 else if(bXSeriesValue
)
2384 //In Case aValues is not a number for X Values...We write X values as 1,2,3....MS Word does the same thing.
2385 pFS
->write( Value
);
2387 bIsNumberValue
= false;
2389 pFS
->endElement( FSNS( XML_c
, XML_v
) );
2390 pFS
->endElement( FSNS( XML_c
, XML_pt
) );
2393 pFS
->endElement( FSNS( XML_c
, XML_numCache
) );
2394 pFS
->endElement( FSNS( XML_c
, XML_numRef
) );
2395 pFS
->endElement( FSNS( XML_c
, nValueType
) );
2398 void ChartExport::exportShapeProps( const Reference
< XPropertySet
>& xPropSet
)
2400 FSHelperPtr pFS
= GetFS();
2401 pFS
->startElement( FSNS( XML_c
, XML_spPr
),
2404 WriteFill( xPropSet
);
2405 WriteOutline( xPropSet
);
2407 pFS
->endElement( FSNS( XML_c
, XML_spPr
) );
2410 void ChartExport::exportTextProps(const Reference
<XPropertySet
>& xPropSet
)
2412 FSHelperPtr pFS
= GetFS();
2413 pFS
->startElement(FSNS(XML_c
, XML_txPr
), FSEND
);
2415 pFS
->startElement(FSNS(XML_a
, XML_bodyPr
), FSEND
);
2416 pFS
->endElement(FSNS(XML_a
, XML_bodyPr
));
2418 pFS
->startElement(FSNS(XML_a
, XML_p
), FSEND
);
2419 pFS
->startElement(FSNS(XML_a
, XML_pPr
), FSEND
);
2421 bool bDummy
= false;
2423 WriteRunProperties(xPropSet
, false, XML_defRPr
, true, bDummy
, nDummy
);
2425 pFS
->endElement(FSNS(XML_a
, XML_pPr
));
2426 pFS
->endElement(FSNS(XML_a
, XML_p
));
2428 pFS
->endElement(FSNS(XML_c
, XML_txPr
));
2431 void ChartExport::InitPlotArea( )
2433 Reference
< XPropertySet
> xDiagramProperties (mxDiagram
, uno::UNO_QUERY
);
2435 // Check for supported services and then the properties provided by this service.
2436 Reference
<lang::XServiceInfo
> xServiceInfo (mxDiagram
, uno::UNO_QUERY
);
2437 if (xServiceInfo
.is())
2439 if (xServiceInfo
->supportsService("com.sun.star.chart.ChartAxisZSupplier"))
2441 xDiagramProperties
->getPropertyValue("HasZAxis") >>= mbHasZAxis
;
2445 xDiagramProperties
->getPropertyValue("Dim3D") >>= mbIs3DChart
;
2447 if( mbHasCategoryLabels
&& mxNewDiagram
.is())
2449 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( mxNewDiagram
) );
2450 if( xCategories
.is() )
2452 mxCategoriesValues
.set( xCategories
->getValues() );
2457 void ChartExport::exportAxes( )
2459 sal_Int32 nSize
= maAxes
.size();
2460 for( sal_Int32 nIdx
= 0; nIdx
< nSize
; nIdx
++ )
2462 exportAxis( maAxes
[nIdx
] );
2468 sal_Int32
getXAxisType(sal_Int32 eChartType
)
2470 if( (eChartType
== chart::TYPEID_SCATTER
)
2471 || (eChartType
== chart::TYPEID_BUBBLE
) )
2473 else if( eChartType
== chart::TYPEID_STOCK
)
2481 void ChartExport::exportAxis(const AxisIdPair
& rAxisIdPair
)
2483 // get some properties from document first
2484 bool bHasXAxisTitle
= false,
2485 bHasYAxisTitle
= false,
2486 bHasZAxisTitle
= false,
2487 bHasSecondaryXAxisTitle
= false,
2488 bHasSecondaryYAxisTitle
= false;
2489 bool bHasXAxisMajorGrid
= false,
2490 bHasXAxisMinorGrid
= false,
2491 bHasYAxisMajorGrid
= false,
2492 bHasYAxisMinorGrid
= false,
2493 bHasZAxisMajorGrid
= false,
2494 bHasZAxisMinorGrid
= false;
2496 Reference
< XPropertySet
> xDiagramProperties (mxDiagram
, uno::UNO_QUERY
);
2498 xDiagramProperties
->getPropertyValue("HasXAxisTitle") >>= bHasXAxisTitle
;
2499 xDiagramProperties
->getPropertyValue("HasYAxisTitle") >>= bHasYAxisTitle
;
2500 xDiagramProperties
->getPropertyValue("HasZAxisTitle") >>= bHasZAxisTitle
;
2501 xDiagramProperties
->getPropertyValue("HasSecondaryXAxisTitle") >>= bHasSecondaryXAxisTitle
;
2502 xDiagramProperties
->getPropertyValue("HasSecondaryYAxisTitle") >>= bHasSecondaryYAxisTitle
;
2504 xDiagramProperties
->getPropertyValue("HasXAxisGrid") >>= bHasXAxisMajorGrid
;
2505 xDiagramProperties
->getPropertyValue("HasYAxisGrid") >>= bHasYAxisMajorGrid
;
2506 xDiagramProperties
->getPropertyValue("HasZAxisGrid") >>= bHasZAxisMajorGrid
;
2508 xDiagramProperties
->getPropertyValue("HasXAxisHelpGrid") >>= bHasXAxisMinorGrid
;
2509 xDiagramProperties
->getPropertyValue("HasYAxisHelpGrid") >>= bHasYAxisMinorGrid
;
2510 xDiagramProperties
->getPropertyValue("HasZAxisHelpGrid") >>= bHasZAxisMinorGrid
;
2512 Reference
< XPropertySet
> xAxisProp
;
2513 Reference
< drawing::XShape
> xAxisTitle
;
2514 Reference
< beans::XPropertySet
> xMajorGrid
;
2515 Reference
< beans::XPropertySet
> xMinorGrid
;
2516 sal_Int32 nAxisType
= XML_catAx
;
2517 const char* sAxPos
= nullptr;
2519 switch( rAxisIdPair
.nAxisType
)
2521 case AXIS_PRIMARY_X
:
2523 Reference
< css::chart::XAxisXSupplier
> xAxisXSupp( mxDiagram
, uno::UNO_QUERY
);
2524 if( xAxisXSupp
.is())
2525 xAxisProp
= xAxisXSupp
->getXAxis();
2526 if( bHasXAxisTitle
)
2527 xAxisTitle
.set( xAxisXSupp
->getXAxisTitle(), uno::UNO_QUERY
);
2528 if( bHasXAxisMajorGrid
)
2529 xMajorGrid
.set( xAxisXSupp
->getXMainGrid(), uno::UNO_QUERY
);
2530 if( bHasXAxisMinorGrid
)
2531 xMinorGrid
.set( xAxisXSupp
->getXHelpGrid(), uno::UNO_QUERY
);
2533 sal_Int32 eChartType
= getChartType();
2534 nAxisType
= getXAxisType(eChartType
);
2535 // FIXME: axPos, need to check axis direction
2539 case AXIS_PRIMARY_Y
:
2541 Reference
< css::chart::XAxisYSupplier
> xAxisYSupp( mxDiagram
, uno::UNO_QUERY
);
2542 if( xAxisYSupp
.is())
2543 xAxisProp
= xAxisYSupp
->getYAxis();
2544 if( bHasYAxisTitle
)
2545 xAxisTitle
.set( xAxisYSupp
->getYAxisTitle(), uno::UNO_QUERY
);
2546 if( bHasYAxisMajorGrid
)
2547 xMajorGrid
.set( xAxisYSupp
->getYMainGrid(), uno::UNO_QUERY
);
2548 if( bHasYAxisMinorGrid
)
2549 xMinorGrid
.set( xAxisYSupp
->getYHelpGrid(), uno::UNO_QUERY
);
2551 nAxisType
= XML_valAx
;
2552 // FIXME: axPos, need to check axis direction
2556 case AXIS_PRIMARY_Z
:
2558 Reference
< css::chart::XAxisZSupplier
> xAxisZSupp( mxDiagram
, uno::UNO_QUERY
);
2559 if( xAxisZSupp
.is())
2560 xAxisProp
= xAxisZSupp
->getZAxis();
2561 if( bHasZAxisTitle
)
2562 xAxisTitle
.set( xAxisZSupp
->getZAxisTitle(), uno::UNO_QUERY
);
2563 if( bHasZAxisMajorGrid
)
2564 xMajorGrid
.set( xAxisZSupp
->getZMainGrid(), uno::UNO_QUERY
);
2565 if( bHasZAxisMinorGrid
)
2566 xMinorGrid
.set( xAxisZSupp
->getZHelpGrid(), uno::UNO_QUERY
);
2568 sal_Int32 eChartType
= getChartType( );
2569 if( (eChartType
== chart::TYPEID_SCATTER
)
2570 || (eChartType
== chart::TYPEID_BUBBLE
) )
2571 nAxisType
= XML_valAx
;
2572 else if( eChartType
== chart::TYPEID_STOCK
)
2573 nAxisType
= XML_dateAx
;
2574 // FIXME: axPos, need to check axis direction
2578 case AXIS_SECONDARY_X
:
2580 Reference
< css::chart::XTwoAxisXSupplier
> xAxisTwoXSupp( mxDiagram
, uno::UNO_QUERY
);
2581 if( xAxisTwoXSupp
.is())
2582 xAxisProp
= xAxisTwoXSupp
->getSecondaryXAxis();
2583 if( bHasSecondaryXAxisTitle
)
2585 Reference
< css::chart::XSecondAxisTitleSupplier
> xAxisSupp( mxDiagram
, uno::UNO_QUERY
);
2586 xAxisTitle
.set( xAxisSupp
->getSecondXAxisTitle(), uno::UNO_QUERY
);
2589 sal_Int32 eChartType
= getChartType();
2590 nAxisType
= getXAxisType(eChartType
);
2591 // FIXME: axPos, need to check axis direction
2595 case AXIS_SECONDARY_Y
:
2597 Reference
< css::chart::XTwoAxisYSupplier
> xAxisTwoYSupp( mxDiagram
, uno::UNO_QUERY
);
2598 if( xAxisTwoYSupp
.is())
2599 xAxisProp
= xAxisTwoYSupp
->getSecondaryYAxis();
2600 if( bHasSecondaryYAxisTitle
)
2602 Reference
< css::chart::XSecondAxisTitleSupplier
> xAxisSupp( mxDiagram
, uno::UNO_QUERY
);
2603 xAxisTitle
.set( xAxisSupp
->getSecondYAxisTitle(), uno::UNO_QUERY
);
2606 nAxisType
= XML_valAx
;
2607 // FIXME: axPos, need to check axis direction
2613 _exportAxis(xAxisProp
, xAxisTitle
, xMajorGrid
, xMinorGrid
, nAxisType
, sAxPos
, rAxisIdPair
);
2616 void ChartExport::_exportAxis(
2617 const Reference
< XPropertySet
>& xAxisProp
,
2618 const Reference
< drawing::XShape
>& xAxisTitle
,
2619 const Reference
< XPropertySet
>& xMajorGrid
,
2620 const Reference
< XPropertySet
>& xMinorGrid
,
2621 sal_Int32 nAxisType
,
2622 const char* sAxisPos
,
2623 const AxisIdPair
& rAxisIdPair
)
2625 FSHelperPtr pFS
= GetFS();
2626 pFS
->startElement( FSNS( XML_c
, nAxisType
),
2628 pFS
->singleElement( FSNS( XML_c
, XML_axId
),
2629 XML_val
, I32S( rAxisIdPair
.nAxisId
),
2632 pFS
->startElement( FSNS( XML_c
, XML_scaling
),
2635 // logBase, min, max
2636 if(GetProperty( xAxisProp
, "Logarithmic" ) )
2638 bool bLogarithmic
= false;
2639 mAny
>>= bLogarithmic
;
2642 // default value is 10?
2643 sal_Int32 nLogBase
= 10;
2644 pFS
->singleElement( FSNS( XML_c
, XML_logBase
),
2645 XML_val
, I32S( nLogBase
),
2650 // orientation: minMax, maxMin
2651 bool bReverseDirection
= false;
2652 if(GetProperty( xAxisProp
, "ReverseDirection" ) )
2653 mAny
>>= bReverseDirection
;
2655 const char* orientation
= bReverseDirection
? "maxMin":"minMax";
2656 pFS
->singleElement( FSNS( XML_c
, XML_orientation
),
2657 XML_val
, orientation
,
2660 bool bAutoMax
= false;
2661 if(GetProperty( xAxisProp
, "AutoMax" ) )
2664 if( !bAutoMax
&& (GetProperty( xAxisProp
, "Max" ) ) )
2668 pFS
->singleElement( FSNS( XML_c
, XML_max
),
2669 XML_val
, IS( dMax
),
2673 bool bAutoMin
= false;
2674 if(GetProperty( xAxisProp
, "AutoMin" ) )
2677 if( !bAutoMin
&& (GetProperty( xAxisProp
, "Min" ) ) )
2681 pFS
->singleElement( FSNS( XML_c
, XML_min
),
2682 XML_val
, IS( dMin
),
2686 pFS
->endElement( FSNS( XML_c
, XML_scaling
) );
2688 bool bVisible
= true;
2689 if( xAxisProp
.is() )
2691 xAxisProp
->getPropertyValue("Visible") >>= bVisible
;
2694 // only export each axis only once non-deleted
2695 bool bDeleted
= maExportedAxis
.find(rAxisIdPair
.nAxisType
) != maExportedAxis
.end();
2698 maExportedAxis
.insert(rAxisIdPair
.nAxisType
);
2700 pFS
->singleElement( FSNS( XML_c
, XML_delete
),
2701 XML_val
, !bDeleted
&& bVisible
? "0" : "1",
2704 // FIXME: axPos, need to check the property "ReverseDirection"
2705 pFS
->singleElement( FSNS( XML_c
, XML_axPos
),
2709 if( xMajorGrid
.is())
2711 pFS
->startElement( FSNS( XML_c
, XML_majorGridlines
),
2713 exportShapeProps( xMajorGrid
);
2714 pFS
->endElement( FSNS( XML_c
, XML_majorGridlines
) );
2718 if( xMinorGrid
.is())
2720 pFS
->startElement( FSNS( XML_c
, XML_minorGridlines
),
2722 exportShapeProps( xMinorGrid
);
2723 pFS
->endElement( FSNS( XML_c
, XML_minorGridlines
) );
2727 if( xAxisTitle
.is() )
2728 exportTitle( xAxisTitle
);
2730 bool bLinkedNumFmt
= true;
2731 if (GetProperty(xAxisProp
, "LinkNumberFormatToSource"))
2732 mAny
>>= bLinkedNumFmt
;
2734 OUString
aNumberFormatString("General");
2735 if (GetProperty(xAxisProp
, "NumberFormat"))
2739 aNumberFormatString
= getNumberFormatCode(nKey
);
2742 OString sNumberFormatString
= OUStringToOString(aNumberFormatString
, RTL_TEXTENCODING_UTF8
);
2743 pFS
->singleElement(FSNS(XML_c
, XML_numFmt
),
2744 XML_formatCode
, sNumberFormatString
.getStr(),
2745 XML_sourceLinked
, bLinkedNumFmt
? "1" : "0",
2749 sal_Int32 nValue
= 0;
2750 if(GetProperty( xAxisProp
, "Marks" ) )
2753 bool bInner
= nValue
& css::chart::ChartAxisMarks::INNER
;
2754 bool bOuter
= nValue
& css::chart::ChartAxisMarks::OUTER
;
2755 const char* majorTickMark
= nullptr;
2756 if( bInner
&& bOuter
)
2757 majorTickMark
= "cross";
2759 majorTickMark
= "in";
2761 majorTickMark
= "out";
2763 majorTickMark
= "none";
2764 pFS
->singleElement( FSNS( XML_c
, XML_majorTickMark
),
2765 XML_val
, majorTickMark
,
2769 if(GetProperty( xAxisProp
, "HelpMarks" ) )
2772 bool bInner
= nValue
& css::chart::ChartAxisMarks::INNER
;
2773 bool bOuter
= nValue
& css::chart::ChartAxisMarks::OUTER
;
2774 const char* minorTickMark
= nullptr;
2775 if( bInner
&& bOuter
)
2776 minorTickMark
= "cross";
2778 minorTickMark
= "in";
2780 minorTickMark
= "out";
2782 minorTickMark
= "none";
2783 pFS
->singleElement( FSNS( XML_c
, XML_minorTickMark
),
2784 XML_val
, minorTickMark
,
2788 const char* sTickLblPos
= nullptr;
2789 bool bDisplayLabel
= true;
2790 if(GetProperty( xAxisProp
, "DisplayLabels" ) )
2791 mAny
>>= bDisplayLabel
;
2792 if( bDisplayLabel
&& (GetProperty( xAxisProp
, "LabelPosition" ) ) )
2794 css::chart::ChartAxisLabelPosition eLabelPosition
= css::chart::ChartAxisLabelPosition_NEAR_AXIS
;
2795 mAny
>>= eLabelPosition
;
2796 switch( eLabelPosition
)
2798 case css::chart::ChartAxisLabelPosition_NEAR_AXIS
:
2799 case css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE
:
2800 sTickLblPos
= "nextTo";
2802 case css::chart::ChartAxisLabelPosition_OUTSIDE_START
:
2803 sTickLblPos
= "low";
2805 case css::chart::ChartAxisLabelPosition_OUTSIDE_END
:
2806 sTickLblPos
= "high";
2809 sTickLblPos
= "nextTo";
2815 sTickLblPos
= "none";
2817 pFS
->singleElement( FSNS( XML_c
, XML_tickLblPos
),
2818 XML_val
, sTickLblPos
,
2822 exportShapeProps( xAxisProp
);
2824 exportTextProps(xAxisProp
);
2826 pFS
->singleElement( FSNS( XML_c
, XML_crossAx
),
2827 XML_val
, I32S( rAxisIdPair
.nCrossAx
),
2830 // crosses & crossesAt
2831 bool bCrossesValue
= false;
2832 const char* sCrosses
= nullptr;
2833 if(GetProperty( xAxisProp
, "CrossoverPosition" ) )
2835 css::chart::ChartAxisPosition
ePosition( css::chart::ChartAxisPosition_ZERO
);
2839 case css::chart::ChartAxisPosition_START
:
2842 case css::chart::ChartAxisPosition_END
:
2845 case css::chart::ChartAxisPosition_ZERO
:
2846 sCrosses
= "autoZero";
2849 bCrossesValue
= true;
2854 if( bCrossesValue
&& GetProperty( xAxisProp
, "CrossoverValue" ) )
2858 pFS
->singleElement( FSNS( XML_c
, XML_crossesAt
),
2859 XML_val
, IS( dValue
),
2864 pFS
->singleElement( FSNS( XML_c
, XML_crosses
),
2869 if( ( nAxisType
== XML_catAx
)
2870 || ( nAxisType
== XML_dateAx
) )
2872 // FIXME: seems not support? use default value,
2873 const char* const isAuto
= "1";
2874 pFS
->singleElement( FSNS( XML_c
, XML_auto
),
2878 if( nAxisType
== XML_catAx
)
2880 // FIXME: seems not support? lblAlgn
2881 const char* const sLblAlgn
= "ctr";
2882 pFS
->singleElement( FSNS( XML_c
, XML_lblAlgn
),
2887 // FIXME: seems not support? lblOffset
2888 sal_Int32 nLblOffset
= 100;
2889 pFS
->singleElement( FSNS( XML_c
, XML_lblOffset
),
2890 XML_val
, I32S( nLblOffset
),
2894 // TODO: MSO does not support random axis cross position for
2895 // category axis, so we ideally need an algorithm that decides
2896 // when to map the crossing to the tick mark and when to the
2897 // middle of the category
2898 sal_Int32 nChartType
= getChartType();
2899 if (nAxisType
== XML_valAx
&& (nChartType
== chart::TYPEID_LINE
|| nChartType
== chart::TYPEID_SCATTER
))
2901 pFS
->singleElement( FSNS( XML_c
, XML_crossBetween
),
2907 bool bAutoStepMain
= false;
2908 if(GetProperty( xAxisProp
, "AutoStepMain" ) )
2909 mAny
>>= bAutoStepMain
;
2911 if( !bAutoStepMain
&& (GetProperty( xAxisProp
, "StepMain" ) ) )
2913 double dMajorUnit
= 0;
2914 mAny
>>= dMajorUnit
;
2915 pFS
->singleElement( FSNS( XML_c
, XML_majorUnit
),
2916 XML_val
, IS( dMajorUnit
),
2920 bool bAutoStepHelp
= false;
2921 if(GetProperty( xAxisProp
, "AutoStepHelp" ) )
2922 mAny
>>= bAutoStepHelp
;
2924 if( !bAutoStepHelp
&& (GetProperty( xAxisProp
, "StepHelp" ) ) )
2926 double dMinorUnit
= 0;
2927 mAny
>>= dMinorUnit
;
2928 pFS
->singleElement( FSNS( XML_c
, XML_minorUnit
),
2929 XML_val
, IS( dMinorUnit
),
2933 if( nAxisType
== XML_valAx
&& GetProperty( xAxisProp
, "DisplayUnits" ) )
2935 bool bDisplayUnits
= false;
2936 mAny
>>= bDisplayUnits
;
2940 if(GetProperty( xAxisProp
, "BuiltInUnit" ))
2945 pFS
->startElement( FSNS( XML_c
, XML_dispUnits
),
2948 OString aBuiltInUnit
= OUStringToOString(aVal
, RTL_TEXTENCODING_UTF8
);
2949 pFS
->singleElement( FSNS( XML_c
, XML_builtInUnit
),
2950 XML_val
, aBuiltInUnit
.getStr(),
2953 pFS
->singleElement(FSNS( XML_c
, XML_dispUnitsLbl
),FSEND
);
2954 pFS
->endElement( FSNS( XML_c
, XML_dispUnits
) );
2960 pFS
->endElement( FSNS( XML_c
, nAxisType
) );
2965 struct LabelPlacementParam
2968 sal_Int32 meDefault
;
2970 std::unordered_set
<sal_Int32
> maAllowedValues
;
2972 LabelPlacementParam() :
2974 meDefault(css::chart::DataLabelPlacement::OUTSIDE
) {}
2978 maAllowedValues
.insert(css::chart::DataLabelPlacement::OUTSIDE
);
2979 maAllowedValues
.insert(css::chart::DataLabelPlacement::INSIDE
);
2980 maAllowedValues
.insert(css::chart::DataLabelPlacement::CENTER
);
2981 maAllowedValues
.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN
);
2982 maAllowedValues
.insert(css::chart::DataLabelPlacement::TOP
);
2983 maAllowedValues
.insert(css::chart::DataLabelPlacement::BOTTOM
);
2984 maAllowedValues
.insert(css::chart::DataLabelPlacement::LEFT
);
2985 maAllowedValues
.insert(css::chart::DataLabelPlacement::RIGHT
);
2986 maAllowedValues
.insert(css::chart::DataLabelPlacement::AVOID_OVERLAP
);
2990 const char* toOOXMLPlacement( sal_Int32 nPlacement
)
2994 case css::chart::DataLabelPlacement::OUTSIDE
: return "outEnd";
2995 case css::chart::DataLabelPlacement::INSIDE
: return "inEnd";
2996 case css::chart::DataLabelPlacement::CENTER
: return "ctr";
2997 case css::chart::DataLabelPlacement::NEAR_ORIGIN
: return "inBase";
2998 case css::chart::DataLabelPlacement::TOP
: return "t";
2999 case css::chart::DataLabelPlacement::BOTTOM
: return "b";
3000 case css::chart::DataLabelPlacement::LEFT
: return "l";
3001 case css::chart::DataLabelPlacement::RIGHT
: return "r";
3002 case css::chart::DataLabelPlacement::AVOID_OVERLAP
: return "bestFit";
3010 void writeLabelProperties(
3011 const FSHelperPtr
& pFS
, const uno::Reference
<beans::XPropertySet
>& xPropSet
, const LabelPlacementParam
& rLabelParam
)
3016 chart2::DataPointLabel aLabel
;
3017 sal_Int32 nLabelBorderWidth
= 0;
3018 sal_Int32 nLabelBorderColor
= 0x00FFFFFF;
3020 xPropSet
->getPropertyValue("Label") >>= aLabel
;
3021 xPropSet
->getPropertyValue("LabelBorderWidth") >>= nLabelBorderWidth
;
3022 xPropSet
->getPropertyValue("LabelBorderColor") >>= nLabelBorderColor
;
3024 if (nLabelBorderWidth
> 0)
3026 pFS
->startElement(FSNS(XML_c
, XML_spPr
), FSEND
);
3027 pFS
->startElement(FSNS(XML_a
, XML_ln
), XML_w
, IS(convertHmmToEmu(nLabelBorderWidth
)), FSEND
);
3028 if (nLabelBorderColor
!= -1)
3030 pFS
->startElement(FSNS(XML_a
, XML_solidFill
), FSEND
);
3032 OString aStr
= OString::number(nLabelBorderColor
, 16).toAsciiUpperCase();
3033 pFS
->singleElement(FSNS(XML_a
, XML_srgbClr
), XML_val
, aStr
.getStr(), FSEND
);
3035 pFS
->endElement(FSNS(XML_a
, XML_solidFill
));
3037 pFS
->endElement(FSNS(XML_a
, XML_ln
));
3038 pFS
->endElement(FSNS(XML_c
, XML_spPr
));
3041 if (rLabelParam
.mbExport
)
3043 sal_Int32 nLabelPlacement
= rLabelParam
.meDefault
;
3044 if (xPropSet
->getPropertyValue("LabelPlacement") >>= nLabelPlacement
)
3046 if (!rLabelParam
.maAllowedValues
.count(nLabelPlacement
))
3047 nLabelPlacement
= rLabelParam
.meDefault
;
3048 pFS
->singleElement(FSNS(XML_c
, XML_dLblPos
), XML_val
, toOOXMLPlacement(nLabelPlacement
), FSEND
);
3052 pFS
->singleElement(FSNS(XML_c
, XML_showLegendKey
), XML_val
, BS(aLabel
.ShowLegendSymbol
), FSEND
);
3053 pFS
->singleElement(FSNS(XML_c
, XML_showVal
), XML_val
, BS(aLabel
.ShowNumber
), FSEND
);
3054 pFS
->singleElement(FSNS(XML_c
, XML_showCatName
), XML_val
, BS(aLabel
.ShowCategoryName
), FSEND
);
3055 pFS
->singleElement(FSNS(XML_c
, XML_showSerName
), XML_val
, BS(false), FSEND
);
3056 pFS
->singleElement(FSNS(XML_c
, XML_showPercent
), XML_val
, BS(aLabel
.ShowNumberInPercent
), FSEND
);
3061 void ChartExport::exportDataLabels(
3062 const uno::Reference
<chart2::XDataSeries
> & xSeries
, sal_Int32 nSeriesLength
, sal_Int32 eChartType
)
3064 if (!xSeries
.is() || nSeriesLength
<= 0)
3067 uno::Reference
<beans::XPropertySet
> xPropSet(xSeries
, uno::UNO_QUERY
);
3071 FSHelperPtr pFS
= GetFS();
3072 pFS
->startElement(FSNS(XML_c
, XML_dLbls
), FSEND
);
3074 uno::Sequence
<sal_Int32
> aAttrLabelIndices
;
3075 xPropSet
->getPropertyValue("AttributedDataPoints") >>= aAttrLabelIndices
;
3077 // We must not export label placement property when the chart type doesn't
3078 // support this option in MS Office, else MS Office would think the file
3079 // is corrupt & refuse to open it.
3081 const chart::TypeGroupInfo
& rInfo
= chart::GetTypeGroupInfo(static_cast<chart::TypeId
>(eChartType
));
3082 LabelPlacementParam aParam
;
3083 aParam
.mbExport
= !mbIs3DChart
;
3084 aParam
.meDefault
= rInfo
.mnDefLabelPos
;
3086 switch (eChartType
) // diagram chart type
3088 case chart::TYPEID_PIE
:
3089 if(getChartType() == chart::TYPEID_DOUGHNUT
)
3090 aParam
.mbExport
= false;
3092 // All pie charts support label placement.
3093 aParam
.mbExport
= true;
3095 case chart::TYPEID_AREA
:
3096 case chart::TYPEID_RADARLINE
:
3097 case chart::TYPEID_RADARAREA
:
3098 // These chart types don't support label placement.
3099 aParam
.mbExport
= false;
3101 case chart::TYPEID_BAR
:
3102 if (mbStacked
|| mbPercent
)
3104 aParam
.maAllowedValues
.clear();
3105 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::CENTER
);
3106 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::INSIDE
);
3107 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN
);
3108 aParam
.meDefault
= css::chart::DataLabelPlacement::CENTER
;
3110 else // Clustered bar chart
3112 aParam
.maAllowedValues
.clear();
3113 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::CENTER
);
3114 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::INSIDE
);
3115 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::OUTSIDE
);
3116 aParam
.maAllowedValues
.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN
);
3117 aParam
.meDefault
= css::chart::DataLabelPlacement::OUTSIDE
;
3124 const sal_Int32
* p
= aAttrLabelIndices
.getConstArray();
3125 const sal_Int32
* pEnd
= p
+ aAttrLabelIndices
.getLength();
3126 for (; p
!= pEnd
; ++p
)
3128 sal_Int32 nIdx
= *p
;
3129 uno::Reference
<beans::XPropertySet
> xLabelPropSet
= xSeries
->getDataPointByIndex(nIdx
);
3130 if (!xLabelPropSet
.is())
3133 // Individual label property that overwrites the baseline.
3134 pFS
->startElement(FSNS(XML_c
, XML_dLbl
), FSEND
);
3135 pFS
->singleElement(FSNS(XML_c
, XML_idx
), XML_val
, I32S(nIdx
), FSEND
);
3136 writeLabelProperties(pFS
, xLabelPropSet
, aParam
);
3137 pFS
->endElement(FSNS(XML_c
, XML_dLbl
));
3140 // Baseline label properties for all labels.
3141 writeLabelProperties(pFS
, xPropSet
, aParam
);
3143 pFS
->singleElement(FSNS(XML_c
, XML_showLeaderLines
),
3147 pFS
->endElement(FSNS(XML_c
, XML_dLbls
));
3150 void ChartExport::exportDataPoints(
3151 const uno::Reference
< beans::XPropertySet
> & xSeriesProperties
,
3152 sal_Int32 nSeriesLength
)
3154 uno::Reference
< chart2::XDataSeries
> xSeries( xSeriesProperties
, uno::UNO_QUERY
);
3155 bool bVaryColorsByPoint
= false;
3156 Sequence
< sal_Int32
> aDataPointSeq
;
3157 if( xSeriesProperties
.is())
3159 Any aAny
= xSeriesProperties
->getPropertyValue( "AttributedDataPoints" );
3160 aAny
>>= aDataPointSeq
;
3161 xSeriesProperties
->getPropertyValue( "VaryColorsByPoint" ) >>= bVaryColorsByPoint
;
3164 const sal_Int32
* pPoints
= aDataPointSeq
.getConstArray();
3166 Reference
< chart2::XColorScheme
> xColorScheme
;
3167 if( mxNewDiagram
.is())
3168 xColorScheme
.set( mxNewDiagram
->getDefaultColorScheme());
3170 if( bVaryColorsByPoint
&& xColorScheme
.is() )
3172 ::std::set
< sal_Int32
> aAttrPointSet
;
3173 ::std::copy( pPoints
, pPoints
+ aDataPointSeq
.getLength(),
3174 ::std::inserter( aAttrPointSet
, aAttrPointSet
.begin()));
3175 const ::std::set
< sal_Int32
>::const_iterator
aEndIt( aAttrPointSet
.end());
3176 for( nElement
= 0; nElement
< nSeriesLength
; ++nElement
)
3178 uno::Reference
< beans::XPropertySet
> xPropSet
;
3179 if( aAttrPointSet
.find( nElement
) != aEndIt
)
3183 xPropSet
= SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3184 xSeries
, nElement
, getModel() );
3186 catch( const uno::Exception
& rEx
)
3188 SAL_WARN( "oox", "Exception caught during Export of data point: " << rEx
.Message
);
3193 // property set only containing the color
3194 xPropSet
.set( new ColorPropertySet( xColorScheme
->getColorByIndex( nElement
)));
3199 FSHelperPtr pFS
= GetFS();
3200 pFS
->startElement( FSNS( XML_c
, XML_dPt
),
3202 pFS
->singleElement( FSNS( XML_c
, XML_idx
),
3203 XML_val
, I32S(nElement
),
3205 exportShapeProps( xPropSet
);
3207 pFS
->endElement( FSNS( XML_c
, XML_dPt
) );
3213 void ChartExport::exportAxesId(bool bPrimaryAxes
)
3215 sal_Int32 nAxisIdx
= lcl_generateRandomValue();
3216 sal_Int32 nAxisIdy
= lcl_generateRandomValue();
3217 AxesType eXAxis
= bPrimaryAxes
? AXIS_PRIMARY_X
: AXIS_SECONDARY_X
;
3218 AxesType eYAxis
= bPrimaryAxes
? AXIS_PRIMARY_Y
: AXIS_SECONDARY_Y
;
3219 maAxes
.push_back( AxisIdPair( eXAxis
, nAxisIdx
, nAxisIdy
) );
3220 maAxes
.push_back( AxisIdPair( eYAxis
, nAxisIdy
, nAxisIdx
) );
3221 FSHelperPtr pFS
= GetFS();
3222 pFS
->singleElement( FSNS( XML_c
, XML_axId
),
3223 XML_val
, I32S( nAxisIdx
),
3225 pFS
->singleElement( FSNS( XML_c
, XML_axId
),
3226 XML_val
, I32S( nAxisIdy
),
3230 sal_Int32 nAxisIdz
= 0;
3231 if( isDeep3dChart() )
3233 nAxisIdz
= lcl_generateRandomValue();
3234 maAxes
.push_back( AxisIdPair( AXIS_PRIMARY_Z
, nAxisIdz
, nAxisIdy
) );
3236 pFS
->singleElement( FSNS( XML_c
, XML_axId
),
3237 XML_val
, I32S( nAxisIdz
),
3242 void ChartExport::exportGrouping( bool isBar
)
3244 FSHelperPtr pFS
= GetFS();
3245 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
3247 if( GetProperty( xPropSet
, "Stacked" ) )
3249 if( GetProperty( xPropSet
, "Percent" ) )
3252 const char* grouping
= nullptr;
3254 grouping
= "stacked";
3256 grouping
= "percentStacked";
3259 if( isBar
&& !isDeep3dChart() )
3261 grouping
= "clustered";
3264 grouping
= "standard";
3266 pFS
->singleElement( FSNS( XML_c
, XML_grouping
),
3271 void ChartExport::exportTrendlines( const Reference
< chart2::XDataSeries
>& xSeries
)
3273 FSHelperPtr pFS
= GetFS();
3274 Reference
< chart2::XRegressionCurveContainer
> xRegressionCurveContainer( xSeries
, UNO_QUERY
);
3275 if( xRegressionCurveContainer
.is() )
3277 Sequence
< Reference
< chart2::XRegressionCurve
> > aRegCurveSeq
= xRegressionCurveContainer
->getRegressionCurves();
3278 const Reference
< chart2::XRegressionCurve
>* pBeg
= aRegCurveSeq
.getConstArray();
3279 const Reference
< chart2::XRegressionCurve
>* pEnd
= pBeg
+ aRegCurveSeq
.getLength();
3280 for( const Reference
< chart2::XRegressionCurve
>* pIt
= pBeg
; pIt
!= pEnd
; ++pIt
)
3282 Reference
< chart2::XRegressionCurve
> xRegCurve
= *pIt
;
3283 if (!xRegCurve
.is())
3286 Reference
< XPropertySet
> xProperties( xRegCurve
, uno::UNO_QUERY
);
3289 Reference
< lang::XServiceName
> xServiceName( xProperties
, UNO_QUERY
);
3290 if( !xServiceName
.is() )
3293 aService
= xServiceName
->getServiceName();
3295 if(aService
!= "com.sun.star.chart2.LinearRegressionCurve" &&
3296 aService
!= "com.sun.star.chart2.ExponentialRegressionCurve" &&
3297 aService
!= "com.sun.star.chart2.LogarithmicRegressionCurve" &&
3298 aService
!= "com.sun.star.chart2.PotentialRegressionCurve" &&
3299 aService
!= "com.sun.star.chart2.PolynomialRegressionCurve" &&
3300 aService
!= "com.sun.star.chart2.MovingAverageRegressionCurve")
3303 pFS
->startElement( FSNS( XML_c
, XML_trendline
), FSEND
);
3306 xProperties
->getPropertyValue("CurveName") >>= aName
;
3307 if(!aName
.isEmpty())
3309 pFS
->startElement( FSNS( XML_c
, XML_name
), FSEND
);
3310 pFS
->writeEscaped(aName
);
3311 pFS
->endElement( FSNS( XML_c
, XML_name
) );
3314 exportShapeProps( xProperties
);
3316 if( aService
== "com.sun.star.chart2.LinearRegressionCurve" )
3318 pFS
->singleElement( FSNS( XML_c
, XML_trendlineType
),
3322 else if( aService
== "com.sun.star.chart2.ExponentialRegressionCurve" )
3324 pFS
->singleElement( FSNS( XML_c
, XML_trendlineType
),
3328 else if( aService
== "com.sun.star.chart2.LogarithmicRegressionCurve" )
3330 pFS
->singleElement( FSNS( XML_c
, XML_trendlineType
),
3334 else if( aService
== "com.sun.star.chart2.PotentialRegressionCurve" )
3336 pFS
->singleElement( FSNS( XML_c
, XML_trendlineType
),
3340 else if( aService
== "com.sun.star.chart2.PolynomialRegressionCurve" )
3342 pFS
->singleElement( FSNS( XML_c
, XML_trendlineType
),
3346 sal_Int32 aDegree
= 2;
3347 xProperties
->getPropertyValue( "PolynomialDegree") >>= aDegree
;
3348 pFS
->singleElement( FSNS( XML_c
, XML_order
),
3349 XML_val
, I32S(aDegree
),
3352 else if( aService
== "com.sun.star.chart2.MovingAverageRegressionCurve" )
3354 pFS
->singleElement( FSNS( XML_c
, XML_trendlineType
),
3355 XML_val
, "movingAvg",
3358 sal_Int32 aPeriod
= 2;
3359 xProperties
->getPropertyValue( "MovingAveragePeriod") >>= aPeriod
;
3361 pFS
->singleElement( FSNS( XML_c
, XML_period
),
3362 XML_val
, I32S(aPeriod
),
3367 // should never happen
3368 // This would produce invalid OOXML files so we check earlier for the type
3372 double fExtrapolateForward
= 0.0;
3373 double fExtrapolateBackward
= 0.0;
3375 xProperties
->getPropertyValue("ExtrapolateForward") >>= fExtrapolateForward
;
3376 xProperties
->getPropertyValue("ExtrapolateBackward") >>= fExtrapolateBackward
;
3378 pFS
->singleElement( FSNS( XML_c
, XML_forward
),
3379 XML_val
, OString::number(fExtrapolateForward
).getStr(),
3382 pFS
->singleElement( FSNS( XML_c
, XML_backward
),
3383 XML_val
, OString::number(fExtrapolateBackward
).getStr(),
3386 bool bForceIntercept
= false;
3387 xProperties
->getPropertyValue("ForceIntercept") >>= bForceIntercept
;
3389 if (bForceIntercept
)
3391 double fInterceptValue
= 0.0;
3392 xProperties
->getPropertyValue("InterceptValue") >>= fInterceptValue
;
3394 pFS
->singleElement( FSNS( XML_c
, XML_intercept
),
3395 XML_val
, OString::number(fInterceptValue
).getStr(),
3399 // Equation properties
3400 Reference
< XPropertySet
> xEquationProperties( xRegCurve
->getEquationProperties() );
3403 bool bShowEquation
= false;
3404 xEquationProperties
->getPropertyValue("ShowEquation") >>= bShowEquation
;
3407 bool bShowCorrelationCoefficient
= false;
3408 xEquationProperties
->getPropertyValue("ShowCorrelationCoefficient") >>= bShowCorrelationCoefficient
;
3410 pFS
->singleElement( FSNS( XML_c
, XML_dispRSqr
),
3411 XML_val
, bShowCorrelationCoefficient
? "1" : "0",
3414 pFS
->singleElement( FSNS( XML_c
, XML_dispEq
),
3415 XML_val
, bShowEquation
? "1" : "0",
3418 pFS
->endElement( FSNS( XML_c
, XML_trendline
) );
3423 void ChartExport::exportMarker(const Reference
< chart2::XDataSeries
>& xSeries
)
3425 Reference
< XPropertySet
> xPropSet( xSeries
, uno::UNO_QUERY
);
3426 chart2::Symbol aSymbol
;
3427 if( GetProperty( xPropSet
, "Symbol" ) )
3430 if(aSymbol
.Style
!= chart2::SymbolStyle_STANDARD
&& aSymbol
.Style
!= chart2::SymbolStyle_AUTO
&& aSymbol
.Style
!= chart2::SymbolStyle_NONE
)
3433 FSHelperPtr pFS
= GetFS();
3434 pFS
->startElement( FSNS( XML_c
, XML_marker
),
3437 sal_Int32 nSymbol
= aSymbol
.StandardSymbol
;
3438 // TODO: more properties support for marker
3439 const char* pSymbolType
= nullptr;
3443 pSymbolType
= "square";
3446 pSymbolType
= "diamond";
3452 pSymbolType
= "triangle";
3455 pSymbolType
= "circle";
3458 pSymbolType
= "star";
3461 pSymbolType
= "x"; // in MS office 2010 built in symbol marker 'X' is represented as 'x'
3464 pSymbolType
= "plus";
3467 pSymbolType
= "dash";
3470 pSymbolType
= "square";
3474 bool bSkipFormatting
= false;
3475 if (aSymbol
.Style
== chart2::SymbolStyle_NONE
)
3477 bSkipFormatting
= true;
3478 pSymbolType
= "none";
3483 pFS
->singleElement( FSNS( XML_c
, XML_symbol
),
3484 XML_val
, pSymbolType
,
3488 if (!bSkipFormatting
)
3490 awt::Size aSymbolSize
= aSymbol
.Size
;
3491 sal_Int32 nSize
= std::max( aSymbolSize
.Width
, aSymbolSize
.Height
);
3493 nSize
= nSize
/250.0*7.0 + 1; // just guessed based on some test cases,
3494 //the value is always 1 less than the actual value.
3495 nSize
= std::min
<sal_Int32
>( 72, std::max
<sal_Int32
>( 2, nSize
) );
3496 pFS
->singleElement( FSNS( XML_c
, XML_size
),
3497 XML_val
, I32S(nSize
),
3500 pFS
->startElement( FSNS( XML_c
, XML_spPr
),
3503 util::Color aColor
= aSymbol
.FillColor
;
3504 if (GetProperty(xPropSet
, "Color"))
3509 pFS
->singleElement(FSNS(XML_a
, XML_noFill
), FSEND
);
3512 WriteSolidFill(aColor
);
3514 pFS
->endElement( FSNS( XML_c
, XML_spPr
) );
3517 pFS
->endElement( FSNS( XML_c
, XML_marker
) );
3520 void ChartExport::exportSmooth()
3522 FSHelperPtr pFS
= GetFS();
3523 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
3524 sal_Int32 nSplineType
= 0;
3525 if( GetProperty( xPropSet
, "SplineType" ) )
3526 mAny
>>= nSplineType
;
3527 const char* pVal
= nSplineType
!= 0 ? "1" : "0";
3528 pFS
->singleElement( FSNS( XML_c
, XML_smooth
),
3533 void ChartExport::exportFirstSliceAng( )
3535 FSHelperPtr pFS
= GetFS();
3536 sal_Int32 nStartingAngle
= 0;
3537 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
3538 if( GetProperty( xPropSet
, "StartingAngle" ) )
3539 mAny
>>= nStartingAngle
;
3541 // convert to ooxml angle
3542 nStartingAngle
= (450 - nStartingAngle
) % 360;
3543 pFS
->singleElement( FSNS( XML_c
, XML_firstSliceAng
),
3544 XML_val
, I32S( nStartingAngle
),
3550 const char* getErrorBarStyle(sal_Int32 nErrorBarStyle
)
3552 switch(nErrorBarStyle
)
3554 case cssc::ErrorBarStyle::NONE
:
3556 case cssc::ErrorBarStyle::VARIANCE
:
3558 case cssc::ErrorBarStyle::STANDARD_DEVIATION
:
3560 case cssc::ErrorBarStyle::ABSOLUTE
:
3562 case cssc::ErrorBarStyle::RELATIVE
:
3563 return "percentage";
3564 case cssc::ErrorBarStyle::ERROR_MARGIN
:
3566 case cssc::ErrorBarStyle::STANDARD_ERROR
:
3568 case cssc::ErrorBarStyle::FROM_DATA
:
3571 assert(false && "can't happen");
3576 Reference
< chart2::data::XDataSequence
> getLabeledSequence(
3577 const uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> >& aSequences
,
3580 OUString aDirection
;
3582 aDirection
= "positive";
3584 aDirection
= "negative";
3586 for( sal_Int32 nI
=0; nI
< aSequences
.getLength(); ++nI
)
3588 if( aSequences
[nI
].is())
3590 uno::Reference
< chart2::data::XDataSequence
> xSequence( aSequences
[nI
]->getValues());
3591 uno::Reference
< beans::XPropertySet
> xSeqProp( xSequence
, uno::UNO_QUERY_THROW
);
3593 if( ( xSeqProp
->getPropertyValue( "Role" ) >>= aRole
) &&
3594 aRole
.match( "error-bars" ) && aRole
.indexOf(aDirection
) >= 0 )
3601 return Reference
< chart2::data::XDataSequence
> ();
3606 void ChartExport::exportErrorBar(const Reference
< XPropertySet
>& xErrorBarProps
, bool bYError
)
3608 sal_Int32 nErrorBarStyle
= cssc::ErrorBarStyle::NONE
;
3609 xErrorBarProps
->getPropertyValue("ErrorBarStyle") >>= nErrorBarStyle
;
3610 const char* pErrorBarStyle
= getErrorBarStyle(nErrorBarStyle
);
3614 FSHelperPtr pFS
= GetFS();
3615 pFS
->startElement( FSNS( XML_c
, XML_errBars
),
3617 pFS
->singleElement( FSNS( XML_c
, XML_errDir
),
3618 XML_val
, bYError
? "y" : "x",
3620 bool bPositive
= false, bNegative
= false;
3621 xErrorBarProps
->getPropertyValue("ShowPositiveError") >>= bPositive
;
3622 xErrorBarProps
->getPropertyValue("ShowNegativeError") >>= bNegative
;
3623 const char* pErrBarType
;
3624 if(bPositive
&& bNegative
)
3625 pErrBarType
= "both";
3627 pErrBarType
= "plus";
3629 pErrBarType
= "minus";
3632 // what the hell should we do now?
3633 // at least this makes the file valid
3634 pErrBarType
= "both";
3636 pFS
->singleElement( FSNS( XML_c
, XML_errBarType
),
3637 XML_val
, pErrBarType
,
3639 pFS
->singleElement( FSNS( XML_c
, XML_errValType
),
3640 XML_val
, pErrorBarStyle
,
3642 pFS
->singleElement( FSNS( XML_c
, XML_noEndCap
),
3645 if(nErrorBarStyle
== cssc::ErrorBarStyle::FROM_DATA
)
3647 uno::Reference
< chart2::data::XDataSource
> xDataSource(xErrorBarProps
, uno::UNO_QUERY
);
3648 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSequences
=
3649 xDataSource
->getDataSequences();
3653 exportSeriesValues(getLabeledSequence(aSequences
, true), XML_plus
);
3658 exportSeriesValues(getLabeledSequence(aSequences
, false), XML_minus
);
3664 if(nErrorBarStyle
== cssc::ErrorBarStyle::STANDARD_DEVIATION
)
3666 xErrorBarProps
->getPropertyValue("Weight") >>= nVal
;
3671 xErrorBarProps
->getPropertyValue("PositiveError") >>= nVal
;
3673 xErrorBarProps
->getPropertyValue("NegativeError") >>= nVal
;
3676 OString aVal
= OString::number(nVal
);
3678 pFS
->singleElement( FSNS( XML_c
, XML_val
),
3679 XML_val
, aVal
.getStr(),
3683 pFS
->endElement( FSNS( XML_c
, XML_errBars
) );
3686 void ChartExport::exportView3D()
3688 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
3689 if( !xPropSet
.is() )
3691 FSHelperPtr pFS
= GetFS();
3692 pFS
->startElement( FSNS( XML_c
, XML_view3D
),
3694 sal_Int32 eChartType
= getChartType( );
3696 if( GetProperty( xPropSet
, "RotationHorizontal" ) )
3698 sal_Int32 nRotationX
= 0;
3699 mAny
>>= nRotationX
;
3700 if( nRotationX
< 0 )
3702 if(eChartType
== chart::TYPEID_PIE
)
3704 /* In OOXML we get value in 0..90 range for pie chart X rotation , whereas we expect it to be in -90..90 range,
3705 so we conver that during import. It is modified in View3DConverter::convertFromModel()
3706 here we convert it back to 0..90 as we received in import */
3707 nRotationX
+= 90; // X rotation (map Chart2 [-179,180] to OOXML [0..90])
3710 nRotationX
+= 360; // X rotation (map Chart2 [-179,180] to OOXML [-90..90])
3712 pFS
->singleElement( FSNS( XML_c
, XML_rotX
),
3713 XML_val
, I32S( nRotationX
),
3717 if( GetProperty( xPropSet
, "RotationVertical" ) )
3719 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
3720 if( eChartType
== chart::TYPEID_PIE
&& GetProperty( xPropSet
, "StartingAngle" ) )
3722 // Y rotation used as 'first pie slice angle' in 3D pie charts
3723 sal_Int32 nStartingAngle
=0;
3724 mAny
>>= nStartingAngle
;
3725 // convert to ooxml angle
3726 nStartingAngle
= (450 - nStartingAngle
) % 360;
3727 pFS
->singleElement( FSNS( XML_c
, XML_rotY
),
3728 XML_val
, I32S( nStartingAngle
),
3733 sal_Int32 nRotationY
= 0;
3734 mAny
>>= nRotationY
;
3735 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
3736 if( nRotationY
< 0 )
3738 pFS
->singleElement( FSNS( XML_c
, XML_rotY
),
3739 XML_val
, I32S( nRotationY
),
3744 if( GetProperty( xPropSet
, "RightAngledAxes" ) )
3746 bool bRightAngled
= false;
3747 mAny
>>= bRightAngled
;
3748 const char* sRightAngled
= bRightAngled
? "1":"0";
3749 pFS
->singleElement( FSNS( XML_c
, XML_rAngAx
),
3750 XML_val
, sRightAngled
,
3754 if( GetProperty( xPropSet
, "Perspective" ) )
3756 sal_Int32 nPerspective
= 0;
3757 mAny
>>= nPerspective
;
3758 // map Chart2 [0,100] to OOXML [0..200]
3760 pFS
->singleElement( FSNS( XML_c
, XML_perspective
),
3761 XML_val
, I32S( nPerspective
),
3764 pFS
->endElement( FSNS( XML_c
, XML_view3D
) );
3767 bool ChartExport::isDeep3dChart()
3769 bool isDeep
= false;
3772 Reference
< XPropertySet
> xPropSet( mxDiagram
, uno::UNO_QUERY
);
3773 if( GetProperty( xPropSet
, "Deep" ) )
3779 OUString
ChartExport::getNumberFormatCode(sal_Int32 nKey
) const
3781 /* XXX if this was called more than one or two times per export the two
3782 * SvNumberFormatter instances and NfKeywordTable should be member
3783 * variables and initialized only once. */
3785 OUString
aCode("General"); // init with fallback
3786 uno::Reference
<util::XNumberFormatsSupplier
> xNumberFormatsSupplier(mxChartModel
, uno::UNO_QUERY_THROW
);
3787 SvNumberFormatsSupplierObj
* pSupplierObj
= SvNumberFormatsSupplierObj::getImplementation( xNumberFormatsSupplier
);
3791 SvNumberFormatter
* pNumberFormatter
= pSupplierObj
->GetNumberFormatter();
3792 if (!pNumberFormatter
)
3795 SvNumberFormatter
aTempFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US
);
3796 NfKeywordTable aKeywords
;
3797 aTempFormatter
.FillKeywordTableForExcel( aKeywords
);
3798 aCode
= pNumberFormatter
->GetFormatStringForExcel( nKey
, aKeywords
, aTempFormatter
);
3806 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */