Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / oox / source / export / chartexport.cxx
blob28f8c6c4d7f8edc61e0b1cebdb538248bef7e556
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
28 #include <cstdio>
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>
98 #include <set>
99 #include <unordered_set>
101 #include <rtl/math.hxx>
103 using namespace css;
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 {
119 namespace {
121 bool isPrimaryAxes(sal_Int32 nIndex)
123 assert(nIndex == 0 || nIndex == 1);
124 return nIndex != 1;
129 class lcl_MatchesRole : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool >
131 public:
132 explicit lcl_MatchesRole( const OUString & aRole ) :
133 m_aRole( aRole )
136 bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
138 if( !xSeq.is() )
139 return false;
140 Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
141 OUString aRole;
143 return ( xProp.is() &&
144 (xProp->getPropertyValue( "Role" ) >>= aRole ) &&
145 m_aRole.equals( aRole ));
148 private:
149 OUString m_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());
180 if( xAxis.is())
182 chart2::ScaleData aScaleData = xAxis->getScaleData();
183 if( aScaleData.Categories.is())
185 xResult.set( aScaleData.Categories );
186 break;
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()) +
199 ", Message: " +
200 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
203 return xResult;
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 );
214 if( xSink.is())
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;
223 if( xChartDoc.is() )
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() )
232 continue;
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 ));
253 if( pMatch != pEnd )
254 return *pMatch;
256 return aNoResult;
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" ) );
276 if( xXValues.is() )
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 )
293 bool bResult=true;
297 sal_Int32 nAxisIndex = 0;
298 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
299 if( xProp.is() )
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()) +
309 ", Message: " +
310 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
313 return bResult;
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())
359 return;
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 ));
368 else
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 )
379 double fNan = 0.0;
380 ::rtl::math::setNan( &fNan );
381 ::std::vector< double > aResult;
383 Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
384 if( xNumSeq.is())
386 Sequence< double > aValues( xNumSeq->getNumericalData());
387 ::std::copy( aValues.begin(), aValues.end(),
388 ::std::back_inserter( aResult ));
390 else if( xSeq.is())
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];
397 return aResult;
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;
434 return eChartTypeId;
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 )
445 , mnSeriesCount(0)
446 , mxChartModel( xModel )
447 , mbHasCategoryLabels( false )
448 , mbHasZAxis( false )
449 , mbIs3DChart( false )
450 , mbStacked(false)
451 , mbPercent(false)
455 sal_Int32 ChartExport::GetChartID( )
457 sal_Int32 nID = GetFB()->GetUniqueId();
458 return nID;
461 sal_Int32 ChartExport::getChartType( )
463 OUString sChartType = mxDiagram->getDiagramType();
464 return lcl_getChartType( sChartType );
467 OUString ChartExport::parseFormula( const OUString& rRange )
469 OUString aResult;
470 Reference< XFormulaParser > xParser;
471 uno::Reference< lang::XMultiServiceFactory > xSF( GetFB()->getModelFactory(), uno::UNO_QUERY );
472 if( xSF.is() )
476 xParser.set( xSF->createInstance("com.sun.star.sheet.FormulaParser"), UNO_QUERY );
478 catch( Exception& )
483 SAL_WARN_IF(!xParser.is(), "oox", "creating formula parser failed");
485 if( xParser.is() )
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 ) );
499 else
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(".$", "!$" );
506 aResult = aRange;
509 return aResult;
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 );
523 if (xNamed.is())
524 sName = xNamed->getName();
526 sal_Int32 nID = GetChartID();
528 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
529 XML_id, I32S( nID ),
530 XML_name, USS( sName ),
531 FSEND );
533 pFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr,
534 FSEND );
536 if( GetDocumentType() == DOCUMENT_PPTX )
537 pFS->singleElementNS( mnXmlNamespace, XML_nvPr,
538 FSEND );
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",
548 FSEND );
549 OUString sId;
550 const char* sFullPath = nullptr;
551 const char* sRelativePath = nullptr;
552 switch( GetDocumentType() )
554 case DOCUMENT_DOCX:
556 sFullPath = "word/charts/chart";
557 sRelativePath = "charts/chart";
558 break;
560 case DOCUMENT_PPTX:
562 sFullPath = "ppt/charts/chart";
563 sRelativePath = "../charts/chart";
564 break;
566 case DOCUMENT_XLSX:
568 sFullPath = "xl/charts/chart";
569 sRelativePath = "../charts/chart";
570 break;
572 default:
574 sFullPath = "charts/chart";
575 sRelativePath = "charts/chart";
576 break;
579 OUString sFullStream = OUStringBuffer()
580 .appendAscii(sFullPath)
581 .append(nChartCount)
582 .append( ".xml" )
583 .makeStringAndClear();
584 OUString sRelativeStream = OUStringBuffer()
585 .appendAscii(sRelativePath)
586 .append(nChartCount)
587 .append( ".xml" )
588 .makeStringAndClear();
589 FSHelperPtr pChart = CreateOutputStream(
590 sFullStream,
591 sRelativeStream,
592 pFS->getOutputStream(),
593 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
594 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
595 &sId );
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 ),
602 FSEND );
604 pFS->endElement( FSNS( XML_a, XML_graphicData ) );
605 pFS->endElement( FSNS( XML_a, XML_graphic ) );
606 pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
608 SetFS( pChart );
609 ExportContent();
612 void ChartExport::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc )
614 if( xChartDoc.is())
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()) +
655 ", Message: " +
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() )
665 return;
666 InitRangeSegmentationProperties( xChartDoc );
667 // TODO: export chart
668 ExportContent_( );
671 void ChartExport::ExportContent_()
673 Reference< css::chart::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
674 if( xChartDoc.is())
676 // determine if data comes from the outside
677 bool bIncludeTable = true;
679 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
680 if( xNewDoc.is())
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;
691 else
693 Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY );
694 if( xServ.is())
696 if( xServ->supportsService("com.sun.star.chart.ChartTableAddressSupplier"))
698 Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY );
699 if( xProp.is())
701 Any aAny;
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 );
724 else
726 OSL_FAIL( "Couldn't export chart due to wrong XModel" );
730 void ChartExport::exportChartSpace( const Reference< css::chart::XChartDocument >& xChartDoc,
731 bool bIncludeTable )
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(),
739 FSEND );
740 // TODO: get the correct editing language
741 pFS->singleElement( FSNS( XML_c, XML_lang ),
742 XML_val, "en-US",
743 FSEND );
745 pFS->singleElement(FSNS( XML_c, XML_roundedCorners),
746 XML_val, "0",
747 FSEND);
749 if( !bIncludeTable )
751 // TODO:external data
753 //XML_chart
754 exportChart(xChartDoc);
756 // TODO: printSettings
757 // TODO: style
758 // TODO: text properties
759 // TODO: shape properties
760 Reference< XPropertySet > xPropSet( xChartDoc->getArea(), uno::UNO_QUERY );
761 if( xPropSet.is() )
762 exportShapeProps( xPropSet );
764 //XML_externalData
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)
775 return;
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 );
800 if( nSepPos > 0)
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(),
812 type,
813 relationPath);
814 pFS->singleElementNS( XML_c, XML_externalData,
815 FSNS(XML_r, XML_id), OUStringToOString(sRelId, RTL_TEXTENCODING_UTF8),
816 FSEND);
820 void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xChartDoc )
822 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
823 mxDiagram.set( xChartDoc->getDiagram() );
824 if( xNewDoc.is())
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");
841 aAny >>= bHasLegend;
843 catch( beans::UnknownPropertyException & )
845 SAL_WARN("oox", "Required property not found in ChartDocument");
847 } // if( xDocPropSet.is())
849 // chart element
851 FSHelperPtr pFS = GetFS();
852 pFS->startElement( FSNS( XML_c, XML_chart ),
853 FSEND );
855 // title
856 if( bHasMainTitle )
858 Reference< drawing::XShape > xShape = xChartDoc->getTitle();
859 if( xShape.is() )
861 exportTitle( xShape );
862 pFS->singleElement( FSNS(XML_c, XML_autoTitleDeleted),
863 XML_val, "0",
864 FSEND);
867 InitPlotArea( );
868 if( mbIs3DChart )
870 exportView3D();
872 // floor
873 Reference< beans::XPropertySet > xFloor( mxNewDiagram->getFloor(), uno::UNO_QUERY );
874 if( xFloor.is() )
876 pFS->startElement( FSNS( XML_c, XML_floor ),
877 FSEND );
878 exportShapeProps( xFloor );
879 pFS->endElement( FSNS( XML_c, XML_floor ) );
882 // sideWall
884 // backWall
885 Reference< beans::XPropertySet > xBackWall( mxNewDiagram->getWall(), uno::UNO_QUERY );
886 if( xBackWall.is() )
888 pFS->startElement( FSNS( XML_c, XML_backWall ),
889 FSEND );
890 exportShapeProps( xBackWall );
891 pFS->endElement( FSNS( XML_c, XML_backWall ) );
895 // plot area
896 exportPlotArea( );
897 // legend
898 if( bHasLegend )
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),
907 FSEND );
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)
916 if (!xPropSet.is())
917 return;
919 sal_Int32 nVal = 0;
920 uno::Any aAny = xPropSet->getPropertyValue("MissingValueTreatment");
921 if (!(aAny >>= nVal))
922 return;
924 const char* pVal = nullptr;
925 switch (nVal)
927 case cssc::MissingValueTreatment::LEAVE_GAP:
928 pVal = "gap";
929 break;
930 case cssc::MissingValueTreatment::USE_ZERO:
931 pVal = "zero";
932 break;
933 case cssc::MissingValueTreatment::CONTINUE:
934 pVal = "span";
935 break;
936 default:
937 SAL_WARN("oox", "unknown MissingValueTreatment value");
938 break;
941 FSHelperPtr pFS = GetFS();
942 pFS->singleElement( FSNS(XML_c, XML_dispBlanksAs),
943 XML_val, pVal,
944 FSEND);
947 void ChartExport::exportLegend( const Reference< css::chart::XChartDocument >& xChartDoc )
949 FSHelperPtr pFS = GetFS();
950 pFS->startElement( FSNS( XML_c, XML_legend ),
951 FSEND );
953 Reference< beans::XPropertySet > xProp( xChartDoc->getLegend(), uno::UNO_QUERY );
954 if( xProp.is() )
956 // position
957 css::chart::ChartLegendPosition aLegendPos = css::chart::ChartLegendPosition_NONE;
960 Any aAny( xProp->getPropertyValue( "Alignment" ));
961 aAny >>= aLegendPos;
963 catch( beans::UnknownPropertyException & )
965 SAL_WARN("oox", "Property Align not found in ChartLegend");
968 const char* strPos = nullptr;
969 switch( aLegendPos )
971 case css::chart::ChartLegendPosition_LEFT:
972 strPos = "l";
973 break;
974 case css::chart::ChartLegendPosition_RIGHT:
975 strPos = "r";
976 break;
977 case css::chart::ChartLegendPosition_TOP:
978 strPos = "t";
979 break;
980 case css::chart::ChartLegendPosition_BOTTOM:
981 strPos = "b";
982 break;
983 case css::chart::ChartLegendPosition_NONE:
984 case css::chart::ChartLegendPosition::ChartLegendPosition_MAKE_FIXED_SIZE:
985 // nothing
986 break;
989 if( strPos != nullptr )
991 pFS->singleElement( FSNS( XML_c, XML_legendPos ),
992 XML_val, strPos,
993 FSEND );
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),
1004 XML_val, "edge",
1005 FSEND);
1006 pFS->singleElement(FSNS(XML_c, XML_yMode),
1007 XML_val, "edge",
1008 FSEND);
1010 double x = aPos.Primary;
1011 double y = aPos.Secondary;
1013 pFS->singleElement(FSNS(XML_c, XML_x),
1014 XML_val, IS(x),
1015 FSEND);
1016 pFS->singleElement(FSNS(XML_c, XML_y),
1017 XML_val, IS(y),
1018 FSEND);
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 ),
1028 XML_val, "0",
1029 FSEND );
1032 // shape properties
1033 exportShapeProps( xProp );
1036 // legendEntry
1038 pFS->endElement( FSNS( XML_c, XML_legend ) );
1041 namespace {
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
1053 nRotation -= 36000;
1055 nRotation *= -600;
1056 return OString::number(nRotation);
1061 void ChartExport::exportTitle( const Reference< XShape >& xShape )
1063 OUString sText;
1064 Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1065 if( xPropSet.is())
1067 xPropSet->getPropertyValue("String") >>= sText;
1069 if( sText.isEmpty() )
1070 return;
1072 FSHelperPtr pFS = GetFS();
1073 pFS->startElement( FSNS( XML_c, XML_title ),
1074 FSEND );
1076 pFS->startElement( FSNS( XML_c, XML_tx ),
1077 FSEND );
1078 pFS->startElement( FSNS( XML_c, XML_rich ),
1079 FSEND );
1081 // TODO: bodyPr
1082 const char* sWritingMode = nullptr;
1083 bool bVertical = false;
1084 xPropSet->getPropertyValue("StackedText") >>= bVertical;
1085 if( 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(),
1094 FSEND );
1095 // TODO: lstStyle
1096 pFS->singleElement( FSNS( XML_a, XML_lstStyle ),
1097 FSEND );
1098 // FIXME: handle multiple paragraphs to parse aText
1099 pFS->startElement( FSNS( XML_a, XML_p ),
1100 FSEND );
1102 pFS->startElement( FSNS( XML_a, XML_pPr ),
1103 FSEND );
1105 bool bDummy = false;
1106 sal_Int32 nDummy;
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 ),
1112 FSEND );
1113 bDummy = false;
1114 WriteRunProperties( xPropSet, false, XML_rPr, true, bDummy, nDummy );
1115 pFS->startElement( FSNS( XML_a, XML_t ),
1116 FSEND );
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),
1132 XML_val, "edge",
1133 FSEND);
1134 pFS->singleElement(FSNS(XML_c, XML_yMode),
1135 XML_val, "edge",
1136 FSEND);
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),
1147 XML_val, "edge",
1148 FSEND);
1149 pFS->singleElement(FSNS(XML_c, XML_hMode),
1150 XML_val, "edge",
1151 FSEND);
1153 pFS->singleElement(FSNS(XML_c, XML_x),
1154 XML_val, IS(x),
1155 FSEND);
1156 pFS->singleElement(FSNS(XML_c, XML_y),
1157 XML_val, IS(y),
1158 FSEND);
1160 pFS->singleElement(FSNS(XML_c, XML_w),
1161 XML_val, "",
1162 FSEND);
1163 pFS->singleElement(FSNS(XML_c, XML_h),
1164 XML_val, "",
1165 FSEND);
1167 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1168 pFS->endElement(FSNS(XML_c, XML_layout));
1171 pFS->singleElement( FSNS(XML_c, XML_overlay),
1172 XML_val, "0",
1173 FSEND);
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())
1182 return;
1184 // plot-area element
1186 FSHelperPtr pFS = GetFS();
1187 pFS->startElement( FSNS( XML_c, XML_plotArea ),
1188 FSEND );
1190 Reference<beans::XPropertySet> xWall(mxNewDiagram, uno::UNO_QUERY);
1191 if( xWall.is() )
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);
1203 // chart type
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 );
1210 if( ! xCTCnt.is())
1211 continue;
1212 mnSeriesCount=0;
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 );
1217 if( ! xDSCnt.is())
1218 return;
1219 Reference< chart2::XChartType > xChartType( aCTSeq[nCTIdx], uno::UNO_QUERY );
1220 if( ! xChartType.is())
1221 continue;
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 );
1230 break;
1232 case chart::TYPEID_AREA:
1234 exportAreaChart( xChartType );
1235 break;
1237 case chart::TYPEID_LINE:
1239 exportLineChart( xChartType );
1240 break;
1242 case chart::TYPEID_BUBBLE:
1244 exportBubbleChart( xChartType );
1245 break;
1247 case chart::TYPEID_OFPIE:
1249 break;
1251 case chart::TYPEID_DOUGHNUT:
1252 case chart::TYPEID_PIE:
1254 exportPieChart( xChartType );
1255 break;
1257 case chart::TYPEID_RADARLINE:
1258 case chart::TYPEID_RADARAREA:
1260 exportRadarChart( xChartType );
1261 break;
1263 case chart::TYPEID_SCATTER:
1265 exportScatterChart( xChartType );
1266 break;
1268 case chart::TYPEID_STOCK:
1270 exportStockChart( xChartType );
1271 break;
1273 case chart::TYPEID_SURFACE:
1275 exportSurfaceChart( xChartType );
1276 break;
1278 default:
1280 SAL_WARN("oox", "ChartExport::exportPlotArea -- not support chart type");
1281 break;
1287 //Axis Data
1288 exportAxes( );
1289 // Data Table
1290 exportDataTable();
1292 // shape properties
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),
1317 XML_val, "inner",
1318 FSEND);
1319 pFS->singleElement(FSNS(XML_c, XML_xMode),
1320 XML_val, "edge",
1321 FSEND);
1322 pFS->singleElement(FSNS(XML_c, XML_yMode),
1323 XML_val, "edge",
1324 FSEND);
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:
1333 y -= (h/2);
1334 break;
1335 case drawing::Alignment_TOP_LEFT:
1336 break;
1337 case drawing::Alignment_BOTTOM_LEFT:
1338 y -= h;
1339 break;
1340 case drawing::Alignment_TOP:
1341 x -= (w/2);
1342 break;
1343 case drawing::Alignment_CENTER:
1344 x -= (w/2);
1345 y -= (h/2);
1346 break;
1347 case drawing::Alignment_BOTTOM:
1348 x -= (w/2);
1349 y -= h;
1350 break;
1351 case drawing::Alignment_TOP_RIGHT:
1352 x -= w;
1353 break;
1354 case drawing::Alignment_BOTTOM_RIGHT:
1355 x -= w;
1356 y -= h;
1357 break;
1358 case drawing::Alignment_RIGHT:
1359 y -= (h/2);
1360 x -= w;
1361 break;
1362 default:
1363 SAL_WARN("oox", "unhandled alignment case for manual layout export");
1366 pFS->singleElement(FSNS(XML_c, XML_x),
1367 XML_val, IS(x),
1368 FSEND);
1370 pFS->singleElement(FSNS(XML_c, XML_y),
1371 XML_val, IS(y),
1372 FSEND);
1374 pFS->singleElement(FSNS(XML_c, XML_w),
1375 XML_val, IS(w),
1376 FSEND);
1378 pFS->singleElement(FSNS(XML_c, XML_h),
1379 XML_val, IS(h),
1380 FSEND);
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 ),
1390 FSEND );
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" ) )
1401 return;
1402 FillStyle aFillStyle( FillStyle_NONE );
1403 xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle;
1404 switch( aFillStyle )
1406 case FillStyle_GRADIENT :
1407 exportGradientFill( xPropSet );
1408 break;
1409 case FillStyle_BITMAP :
1410 exportBitmapFill( xPropSet );
1411 break;
1412 default:
1413 WriteFill( xPropSet );
1417 void ChartExport::exportBitmapFill( const Reference< XPropertySet >& xPropSet )
1419 if( xPropSet.is() )
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 )
1445 if( xPropSet.is() )
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)
1465 SAL_INFO("oox",
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),
1491 FSEND );
1492 if (bShowHBorder)
1493 pFS->singleElement( FSNS( XML_c, XML_showHorzBorder ),
1494 XML_val, "1",
1495 FSEND );
1496 if (bShowVBorder)
1497 pFS->singleElement( FSNS( XML_c, XML_showVertBorder ),
1498 XML_val, "1",
1499 FSEND );
1500 if (bShowOutline)
1501 pFS->singleElement( FSNS( XML_c, XML_showOutline ),
1502 XML_val, "1",
1503 FSEND );
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;
1513 if( mbIs3DChart )
1514 nTypeId = XML_area3DChart;
1515 pFS->startElement( FSNS( XML_c, nTypeId ),
1516 FSEND );
1518 exportGrouping( );
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;
1529 if( mbIs3DChart )
1530 nTypeId = XML_bar3DChart;
1531 FSHelperPtr pFS = GetFS();
1532 pFS->startElement( FSNS( XML_c, nTypeId ),
1533 FSEND );
1534 // bar direction
1535 bool bVertical = false;
1536 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
1537 if( GetProperty( xPropSet, "Vertical" ) )
1538 mAny >>= bVertical;
1540 const char* bardir = bVertical? "bar":"col";
1541 pFS->singleElement( FSNS( XML_c, XML_barDir ),
1542 XML_val, bardir,
1543 FSEND );
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 ),
1563 FSEND );
1567 if( mbIs3DChart )
1569 // Shape
1570 namespace cssc = css::chart;
1571 sal_Int32 nGeom3d = cssc::ChartSolidType::RECTANGULAR_SOLID;
1572 if( xPropSet.is() && GetProperty( xPropSet, "SolidType") )
1573 mAny >>= nGeom3d;
1574 const char* sShapeType = nullptr;
1575 switch( nGeom3d )
1577 case cssc::ChartSolidType::RECTANGULAR_SOLID:
1578 sShapeType = "box";
1579 break;
1580 case cssc::ChartSolidType::CONE:
1581 sShapeType = "cone";
1582 break;
1583 case cssc::ChartSolidType::CYLINDER:
1584 sShapeType = "cylinder";
1585 break;
1586 case cssc::ChartSolidType::PYRAMID:
1587 sShapeType = "pyramid";
1588 break;
1590 pFS->singleElement( FSNS( XML_c, XML_shape ),
1591 XML_val, sShapeType,
1592 FSEND );
1595 //overlap
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 ),
1605 FSEND );
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 ),
1618 FSEND );
1620 exportVaryColors(xChartType);
1622 bool bPrimaryAxes = true;
1623 exportAllSeries(xChartType, bPrimaryAxes);
1625 pFS->singleElement(FSNS(XML_c, XML_bubble3D),
1626 XML_val, "0",
1627 FSEND);
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 ),
1638 FSEND );
1640 exportVaryColors(xChartType);
1642 bool bPrimaryAxes = true;
1643 exportAllSeries(xChartType, bPrimaryAxes);
1644 // firstSliceAng
1645 exportFirstSliceAng( );
1646 //FIXME: holeSize
1647 sal_Int32 nHoleSize = 50;
1648 pFS->singleElement( FSNS( XML_c, XML_holeSize ),
1649 XML_val, I32S( nHoleSize ),
1650 FSEND );
1652 pFS->endElement( FSNS( XML_c, XML_doughnutChart ) );
1655 namespace {
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 );
1663 if(xDSCnt.is())
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);
1670 if (!xPropSet.is())
1671 continue;
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)
1706 continue;
1708 sal_Int32 nTypeId = XML_lineChart;
1709 if( mbIs3DChart )
1710 nTypeId = XML_line3DChart;
1711 pFS->startElement( FSNS( XML_c, nTypeId ),
1712 FSEND );
1714 exportVaryColors(xChartType);
1716 exportGrouping( );
1717 // TODO: show marker symbol in series?
1718 bool bPrimaryAxes = true;
1719 exportSeries(xChartType, *itr, bPrimaryAxes);
1721 // show marker?
1722 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
1723 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
1724 if( GetProperty( xPropSet, "SymbolType" ) )
1725 mAny >>= nSymbolType;
1727 if( !mbIs3DChart )
1729 exportHiLowLines();
1730 exportUpDownBars(xChartType);
1731 const char* marker = nSymbolType == css::chart::ChartSymbolType::NONE? "0":"1";
1732 pFS->singleElement( FSNS( XML_c, XML_marker ),
1733 XML_val, marker,
1734 FSEND );
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 );
1749 return;
1751 FSHelperPtr pFS = GetFS();
1752 sal_Int32 nTypeId = XML_pieChart;
1753 if( mbIs3DChart )
1754 nTypeId = XML_pie3DChart;
1755 pFS->startElement( FSNS( XML_c, nTypeId ),
1756 FSEND );
1758 exportVaryColors(xChartType);
1760 bool bPrimaryAxes = true;
1761 exportAllSeries(xChartType, bPrimaryAxes);
1763 if( !mbIs3DChart )
1765 // firstSliceAng
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 ),
1776 FSEND );
1778 // radarStyle
1779 sal_Int32 eChartType = getChartType( );
1780 const char* radarStyle = nullptr;
1781 if( eChartType == chart::TYPEID_RADARAREA )
1782 radarStyle = "filled";
1783 else
1784 radarStyle = "marker";
1785 pFS->singleElement( FSNS( XML_c, XML_radarStyle ),
1786 XML_val, radarStyle,
1787 FSEND );
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)
1805 continue;
1807 pFS->startElement( FSNS( XML_c, XML_scatterChart ),
1808 FSEND );
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,
1824 FSEND );
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 ),
1840 FSEND );
1842 bool bPrimaryAxes = true;
1843 Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
1844 if(xDSCnt.is())
1845 exportCandleStickSeries( xDSCnt->getDataSeries(), bPrimaryAxes );
1847 // export stock properties
1848 Reference< css::chart::XStatisticDisplay > xStockPropProvider( mxDiagram, uno::UNO_QUERY );
1849 if( xStockPropProvider.is())
1851 exportHiLowLines();
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())
1867 return;
1869 Reference< beans::XPropertySet > xStockPropSet = xChartPropProvider->getMinMaxLine();
1870 if( !xStockPropSet.is() )
1871 return;
1873 pFS->startElement( FSNS( XML_c, XML_hiLowLines ),
1874 FSEND );
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")
1882 return;
1884 FSHelperPtr pFS = GetFS();
1885 // export the chart property
1886 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
1887 if(xChartPropProvider.is())
1889 // updownbar
1890 pFS->startElement( FSNS( XML_c, XML_upDownBars ),
1891 FSEND );
1892 // TODO: gapWidth
1893 sal_Int32 nGapWidth = 150;
1894 pFS->singleElement( FSNS( XML_c, XML_gapWidth ),
1895 XML_val, I32S( nGapWidth ),
1896 FSEND );
1898 Reference< beans::XPropertySet > xChartPropSet = xChartPropProvider->getUpBar();
1899 if( xChartPropSet.is() )
1901 pFS->startElement( FSNS( XML_c, XML_upBars ),
1902 FSEND );
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 ),
1915 FSEND );
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;
1930 if( mbIs3DChart )
1931 nTypeId = XML_surface3DChart;
1932 pFS->startElement( FSNS( XML_c, nTypeId ),
1933 FSEND );
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 );
1945 if( ! xDSCnt.is())
1946 return;
1948 // export dataseries for current chart-type
1949 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
1950 exportSeries(xChartType, aSeriesSeq, rPrimaryAxes);
1953 namespace {
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);
1964 if (xSource.is())
1965 return xSource;
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",
1985 FSEND);
1987 catch (...)
1989 pFS->singleElement(FSNS(XML_c, XML_varyColors),
1990 XML_val, "0",
1991 FSEND);
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 )
2004 // export series
2005 Reference< chart2::data::XDataSource > xSource( rSeriesSeq[nSeriesIdx], uno::UNO_QUERY );
2006 if( xSource.is())
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 )
2020 OUString aRole;
2021 Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2022 if( nMainSequenceIndex==-1 )
2024 Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2025 if( xSeqProp.is())
2026 xSeqProp->getPropertyValue("Role") >>= aRole;
2027 // "main" sequence
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 ),
2046 FSEND );
2048 // TODO: idx and order
2049 pFS->singleElement( FSNS( XML_c, XML_idx ),
2050 XML_val, I32S(mnSeriesCount),
2051 FSEND );
2052 pFS->singleElement( FSNS( XML_c, XML_order ),
2053 XML_val, I32S(mnSeriesCount++),
2054 FSEND );
2056 // export label
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),
2083 XML_val, "0",
2084 FSEND);
2086 break;
2087 case chart::TYPEID_LINE:
2089 exportMarker(xDataSeries);
2090 break;
2092 case chart::TYPEID_PIE:
2093 case chart::TYPEID_DOUGHNUT:
2095 if( xOldPropSet.is() && GetProperty( xOldPropSet, "SegmentOffset") )
2097 sal_Int32 nOffset = 0;
2098 mAny >>= nOffset;
2099 pFS->singleElement( FSNS( XML_c, XML_explosion ),
2100 XML_val, I32S( nOffset ),
2101 FSEND );
2103 break;
2105 case chart::TYPEID_SCATTER:
2107 exportMarker(xDataSeries);
2108 break;
2110 case chart::TYPEID_RADARLINE:
2112 exportMarker(xDataSeries);
2113 break;
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) )
2151 // export xVal
2152 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-x" ) );
2153 if( xSequence.is() )
2155 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2156 if( xValues.is() )
2157 exportSeriesValues( xValues, XML_xVal );
2161 if( eChartType == chart::TYPEID_BUBBLE )
2163 // export yVal
2164 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-y" ) );
2165 if( xSequence.is() )
2167 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2168 if( xValues.is() )
2169 exportSeriesValues( xValues, XML_yVal );
2173 // export values
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 )
2186 exportSmooth();
2188 pFS->endElement( FSNS( XML_c, XML_ser ) );
2195 void ChartExport::exportCandleStickSeries(
2196 const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
2197 bool& rPrimaryAxes)
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 );
2205 if( xSource.is())
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 ),
2225 FSEND );
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),
2231 FSEND );
2232 pFS->singleElement( FSNS( XML_c, XML_order ),
2233 XML_val, I32S(idx+1),
2234 FSEND );
2236 // export label
2237 if( xLabelSeq.is() )
2238 exportSeriesText( xLabelSeq );
2240 // TODO:export shape properties
2242 // export categories
2243 if( mxCategoriesValues.is() )
2244 exportSeriesCategory( mxCategoriesValues );
2246 // export values
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 ),
2262 FSEND );
2264 OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
2265 aCellRange = parseFormula( aCellRange );
2266 pFS->startElement( FSNS( XML_c, XML_strRef ),
2267 FSEND );
2269 pFS->startElement( FSNS( XML_c, XML_f ),
2270 FSEND );
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 ),
2276 FSEND );
2277 pFS->singleElement( FSNS( XML_c, XML_ptCount ),
2278 XML_val, "1",
2279 FSEND );
2280 pFS->startElement( FSNS( XML_c, XML_pt ),
2281 XML_idx, "0",
2282 FSEND );
2283 pFS->startElement( FSNS( XML_c, XML_v ),
2284 FSEND );
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 ),
2297 FSEND );
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 ),
2303 FSEND );
2305 pFS->startElement( FSNS( XML_c, XML_f ),
2306 FSEND );
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 ),
2314 FSEND );
2315 pFS->singleElement( FSNS( XML_c, XML_ptCount ),
2316 XML_val, I32S( ptCount ),
2317 FSEND );
2318 for( sal_Int32 i = 0; i < ptCount; i++ )
2320 pFS->startElement( FSNS( XML_c, XML_pt ),
2321 XML_idx, I32S( i ),
2322 FSEND );
2323 pFS->startElement( FSNS( XML_c, XML_v ),
2324 FSEND );
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 ),
2339 FSEND );
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 ),
2345 FSEND );
2347 pFS->startElement( FSNS( XML_c, XML_f ),
2348 FSEND );
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 ),
2356 FSEND );
2357 pFS->startElement( FSNS( XML_c, XML_formatCode ),
2358 FSEND );
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 ),
2364 FSEND );
2366 bool bIsNumberValue = true;
2367 bool bXSeriesValue = false;
2368 double Value = 1.0;
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 ),
2376 XML_idx, I32S( i ),
2377 FSEND );
2378 pFS->startElement( FSNS( XML_c, XML_v ),
2379 FSEND );
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 );
2386 Value = Value + 1;
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 ),
2402 FSEND );
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;
2422 sal_Int32 nDummy;
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] );
2466 namespace {
2468 sal_Int32 getXAxisType(sal_Int32 eChartType)
2470 if( (eChartType == chart::TYPEID_SCATTER)
2471 || (eChartType == chart::TYPEID_BUBBLE) )
2472 return XML_valAx;
2473 else if( eChartType == chart::TYPEID_STOCK )
2474 return XML_dateAx;
2476 return XML_catAx;
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
2536 sAxPos = "b";
2537 break;
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
2553 sAxPos = "l";
2554 break;
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
2575 sAxPos = "b";
2576 break;
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
2592 sAxPos = "t";
2593 break;
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
2608 sAxPos = "r";
2609 break;
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 ),
2627 FSEND );
2628 pFS->singleElement( FSNS( XML_c, XML_axId ),
2629 XML_val, I32S( rAxisIdPair.nAxisId ),
2630 FSEND );
2632 pFS->startElement( FSNS( XML_c, XML_scaling ),
2633 FSEND );
2635 // logBase, min, max
2636 if(GetProperty( xAxisProp, "Logarithmic" ) )
2638 bool bLogarithmic = false;
2639 mAny >>= bLogarithmic;
2640 if( bLogarithmic )
2642 // default value is 10?
2643 sal_Int32 nLogBase = 10;
2644 pFS->singleElement( FSNS( XML_c, XML_logBase ),
2645 XML_val, I32S( nLogBase ),
2646 FSEND );
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,
2658 FSEND );
2660 bool bAutoMax = false;
2661 if(GetProperty( xAxisProp, "AutoMax" ) )
2662 mAny >>= bAutoMax;
2664 if( !bAutoMax && (GetProperty( xAxisProp, "Max" ) ) )
2666 double dMax = 0;
2667 mAny >>= dMax;
2668 pFS->singleElement( FSNS( XML_c, XML_max ),
2669 XML_val, IS( dMax ),
2670 FSEND );
2673 bool bAutoMin = false;
2674 if(GetProperty( xAxisProp, "AutoMin" ) )
2675 mAny >>= bAutoMin;
2677 if( !bAutoMin && (GetProperty( xAxisProp, "Min" ) ) )
2679 double dMin = 0;
2680 mAny >>= dMin;
2681 pFS->singleElement( FSNS( XML_c, XML_min ),
2682 XML_val, IS( dMin ),
2683 FSEND );
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();
2697 if (!bDeleted)
2698 maExportedAxis.insert(rAxisIdPair.nAxisType);
2700 pFS->singleElement( FSNS( XML_c, XML_delete ),
2701 XML_val, !bDeleted && bVisible ? "0" : "1",
2702 FSEND );
2704 // FIXME: axPos, need to check the property "ReverseDirection"
2705 pFS->singleElement( FSNS( XML_c, XML_axPos ),
2706 XML_val, sAxisPos,
2707 FSEND );
2708 // major grid line
2709 if( xMajorGrid.is())
2711 pFS->startElement( FSNS( XML_c, XML_majorGridlines ),
2712 FSEND );
2713 exportShapeProps( xMajorGrid );
2714 pFS->endElement( FSNS( XML_c, XML_majorGridlines ) );
2717 // minor grid line
2718 if( xMinorGrid.is())
2720 pFS->startElement( FSNS( XML_c, XML_minorGridlines ),
2721 FSEND );
2722 exportShapeProps( xMinorGrid );
2723 pFS->endElement( FSNS( XML_c, XML_minorGridlines ) );
2726 // title
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"))
2737 sal_Int32 nKey = 0;
2738 mAny >>= nKey;
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",
2746 FSEND);
2748 // majorTickMark
2749 sal_Int32 nValue = 0;
2750 if(GetProperty( xAxisProp, "Marks" ) )
2752 mAny >>= nValue;
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";
2758 else if( bInner )
2759 majorTickMark = "in";
2760 else if( bOuter )
2761 majorTickMark = "out";
2762 else
2763 majorTickMark = "none";
2764 pFS->singleElement( FSNS( XML_c, XML_majorTickMark ),
2765 XML_val, majorTickMark,
2766 FSEND );
2768 // minorTickMark
2769 if(GetProperty( xAxisProp, "HelpMarks" ) )
2771 mAny >>= nValue;
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";
2777 else if( bInner )
2778 minorTickMark = "in";
2779 else if( bOuter )
2780 minorTickMark = "out";
2781 else
2782 minorTickMark = "none";
2783 pFS->singleElement( FSNS( XML_c, XML_minorTickMark ),
2784 XML_val, minorTickMark,
2785 FSEND );
2787 // tickLblPos
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";
2801 break;
2802 case css::chart::ChartAxisLabelPosition_OUTSIDE_START:
2803 sTickLblPos = "low";
2804 break;
2805 case css::chart::ChartAxisLabelPosition_OUTSIDE_END:
2806 sTickLblPos = "high";
2807 break;
2808 default:
2809 sTickLblPos = "nextTo";
2810 break;
2813 else
2815 sTickLblPos = "none";
2817 pFS->singleElement( FSNS( XML_c, XML_tickLblPos ),
2818 XML_val, sTickLblPos,
2819 FSEND );
2821 // shape properties
2822 exportShapeProps( xAxisProp );
2824 exportTextProps(xAxisProp);
2826 pFS->singleElement( FSNS( XML_c, XML_crossAx ),
2827 XML_val, I32S( rAxisIdPair.nCrossAx ),
2828 FSEND );
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 );
2836 mAny >>= ePosition;
2837 switch( ePosition )
2839 case css::chart::ChartAxisPosition_START:
2840 sCrosses = "min";
2841 break;
2842 case css::chart::ChartAxisPosition_END:
2843 sCrosses = "max";
2844 break;
2845 case css::chart::ChartAxisPosition_ZERO:
2846 sCrosses = "autoZero";
2847 break;
2848 default:
2849 bCrossesValue = true;
2850 break;
2854 if( bCrossesValue && GetProperty( xAxisProp, "CrossoverValue" ) )
2856 double dValue = 0;
2857 mAny >>= dValue;
2858 pFS->singleElement( FSNS( XML_c, XML_crossesAt ),
2859 XML_val, IS( dValue ),
2860 FSEND );
2862 else
2864 pFS->singleElement( FSNS( XML_c, XML_crosses ),
2865 XML_val, sCrosses,
2866 FSEND );
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 ),
2875 XML_val, isAuto,
2876 FSEND );
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 ),
2883 XML_val, sLblAlgn,
2884 FSEND );
2887 // FIXME: seems not support? lblOffset
2888 sal_Int32 nLblOffset = 100;
2889 pFS->singleElement( FSNS( XML_c, XML_lblOffset ),
2890 XML_val, I32S( nLblOffset ),
2891 FSEND );
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 ),
2902 XML_val, "midCat",
2903 FSEND );
2906 // majorUnit
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 ),
2917 FSEND );
2919 // minorUnit
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 ),
2930 FSEND );
2933 if( nAxisType == XML_valAx && GetProperty( xAxisProp, "DisplayUnits" ) )
2935 bool bDisplayUnits = false;
2936 mAny >>= bDisplayUnits;
2937 if(bDisplayUnits)
2939 OUString aVal;
2940 if(GetProperty( xAxisProp, "BuiltInUnit" ))
2942 mAny >>= aVal;
2943 if(!aVal.isEmpty())
2945 pFS->startElement( FSNS( XML_c, XML_dispUnits ),
2946 FSEND );
2948 OString aBuiltInUnit = OUStringToOString(aVal, RTL_TEXTENCODING_UTF8);
2949 pFS->singleElement( FSNS( XML_c, XML_builtInUnit ),
2950 XML_val, aBuiltInUnit.getStr(),
2951 FSEND );
2953 pFS->singleElement(FSNS( XML_c, XML_dispUnitsLbl ),FSEND);
2954 pFS->endElement( FSNS( XML_c, XML_dispUnits ) );
2960 pFS->endElement( FSNS( XML_c, nAxisType ) );
2963 namespace {
2965 struct LabelPlacementParam
2967 bool mbExport;
2968 sal_Int32 meDefault;
2970 std::unordered_set<sal_Int32> maAllowedValues;
2972 LabelPlacementParam() :
2973 mbExport(true),
2974 meDefault(css::chart::DataLabelPlacement::OUTSIDE) {}
2976 void allowAll()
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 )
2992 switch (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";
3003 default:
3007 return "outEnd";
3010 void writeLabelProperties(
3011 const FSHelperPtr& pFS, const uno::Reference<beans::XPropertySet>& xPropSet, const LabelPlacementParam& rLabelParam )
3013 if (!xPropSet.is())
3014 return;
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)
3065 return;
3067 uno::Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
3068 if (!xPropSet.is())
3069 return;
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;
3085 aParam.allowAll();
3086 switch (eChartType) // diagram chart type
3088 case chart::TYPEID_PIE:
3089 if(getChartType() == chart::TYPEID_DOUGHNUT)
3090 aParam.mbExport = false;
3091 else
3092 // All pie charts support label placement.
3093 aParam.mbExport = true;
3094 break;
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;
3100 break;
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;
3119 break;
3120 default:
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())
3131 continue;
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),
3144 XML_val, "0",
3145 FSEND);
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();
3165 sal_Int32 nElement;
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 );
3191 else
3193 // property set only containing the color
3194 xPropSet.set( new ColorPropertySet( xColorScheme->getColorByIndex( nElement )));
3197 if( xPropSet.is() )
3199 FSHelperPtr pFS = GetFS();
3200 pFS->startElement( FSNS( XML_c, XML_dPt ),
3201 FSEND );
3202 pFS->singleElement( FSNS( XML_c, XML_idx ),
3203 XML_val, I32S(nElement),
3204 FSEND );
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 ),
3224 FSEND );
3225 pFS->singleElement( FSNS( XML_c, XML_axId ),
3226 XML_val, I32S( nAxisIdy ),
3227 FSEND );
3228 if (mbHasZAxis)
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 ),
3238 FSEND );
3242 void ChartExport::exportGrouping( bool isBar )
3244 FSHelperPtr pFS = GetFS();
3245 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3246 // grouping
3247 if( GetProperty( xPropSet, "Stacked" ) )
3248 mAny >>= mbStacked;
3249 if( GetProperty( xPropSet, "Percent" ) )
3250 mAny >>= mbPercent;
3252 const char* grouping = nullptr;
3253 if (mbStacked)
3254 grouping = "stacked";
3255 else if (mbPercent)
3256 grouping = "percentStacked";
3257 else
3259 if( isBar && !isDeep3dChart() )
3261 grouping = "clustered";
3263 else
3264 grouping = "standard";
3266 pFS->singleElement( FSNS( XML_c, XML_grouping ),
3267 XML_val, grouping,
3268 FSEND );
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())
3284 continue;
3286 Reference< XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
3288 OUString aService;
3289 Reference< lang::XServiceName > xServiceName( xProperties, UNO_QUERY );
3290 if( !xServiceName.is() )
3291 continue;
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")
3301 continue;
3303 pFS->startElement( FSNS( XML_c, XML_trendline ), FSEND );
3305 OUString aName;
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 ),
3319 XML_val, "linear",
3320 FSEND );
3322 else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
3324 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3325 XML_val, "exp",
3326 FSEND );
3328 else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
3330 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3331 XML_val, "log",
3332 FSEND );
3334 else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
3336 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3337 XML_val, "power",
3338 FSEND );
3340 else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
3342 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3343 XML_val, "poly",
3344 FSEND );
3346 sal_Int32 aDegree = 2;
3347 xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
3348 pFS->singleElement( FSNS( XML_c, XML_order ),
3349 XML_val, I32S(aDegree),
3350 FSEND );
3352 else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
3354 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3355 XML_val, "movingAvg",
3356 FSEND );
3358 sal_Int32 aPeriod = 2;
3359 xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
3361 pFS->singleElement( FSNS( XML_c, XML_period ),
3362 XML_val, I32S(aPeriod),
3363 FSEND );
3365 else
3367 // should never happen
3368 // This would produce invalid OOXML files so we check earlier for the type
3369 assert(false);
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(),
3380 FSEND );
3382 pFS->singleElement( FSNS( XML_c, XML_backward ),
3383 XML_val, OString::number(fExtrapolateBackward).getStr(),
3384 FSEND );
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(),
3396 FSEND );
3399 // Equation properties
3400 Reference< XPropertySet > xEquationProperties( xRegCurve->getEquationProperties() );
3402 // Show Equation
3403 bool bShowEquation = false;
3404 xEquationProperties->getPropertyValue("ShowEquation") >>= bShowEquation;
3406 // Show R^2
3407 bool bShowCorrelationCoefficient = false;
3408 xEquationProperties->getPropertyValue("ShowCorrelationCoefficient") >>= bShowCorrelationCoefficient;
3410 pFS->singleElement( FSNS( XML_c, XML_dispRSqr ),
3411 XML_val, bShowCorrelationCoefficient ? "1" : "0",
3412 FSEND );
3414 pFS->singleElement( FSNS( XML_c, XML_dispEq ),
3415 XML_val, bShowEquation ? "1" : "0",
3416 FSEND );
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" ) )
3428 mAny >>= aSymbol;
3430 if(aSymbol.Style != chart2::SymbolStyle_STANDARD && aSymbol.Style != chart2::SymbolStyle_AUTO && aSymbol.Style != chart2::SymbolStyle_NONE)
3431 return;
3433 FSHelperPtr pFS = GetFS();
3434 pFS->startElement( FSNS( XML_c, XML_marker ),
3435 FSEND );
3437 sal_Int32 nSymbol = aSymbol.StandardSymbol;
3438 // TODO: more properties support for marker
3439 const char* pSymbolType = nullptr;
3440 switch( nSymbol )
3442 case 0:
3443 pSymbolType = "square";
3444 break;
3445 case 1:
3446 pSymbolType = "diamond";
3447 break;
3448 case 2:
3449 case 3:
3450 case 4:
3451 case 5:
3452 pSymbolType = "triangle";
3453 break;
3454 case 8:
3455 pSymbolType = "circle";
3456 break;
3457 case 9:
3458 pSymbolType = "star";
3459 break;
3460 case 10:
3461 pSymbolType = "x"; // in MS office 2010 built in symbol marker 'X' is represented as 'x'
3462 break;
3463 case 11:
3464 pSymbolType = "plus";
3465 break;
3466 case 13:
3467 pSymbolType = "dash";
3468 break;
3469 default:
3470 pSymbolType = "square";
3471 break;
3474 bool bSkipFormatting = false;
3475 if (aSymbol.Style == chart2::SymbolStyle_NONE)
3477 bSkipFormatting = true;
3478 pSymbolType = "none";
3481 if( pSymbolType )
3483 pFS->singleElement( FSNS( XML_c, XML_symbol ),
3484 XML_val, pSymbolType,
3485 FSEND );
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),
3498 FSEND );
3500 pFS->startElement( FSNS( XML_c, XML_spPr ),
3501 FSEND );
3503 util::Color aColor = aSymbol.FillColor;
3504 if (GetProperty(xPropSet, "Color"))
3505 mAny >>= aColor;
3507 if (aColor == -1)
3509 pFS->singleElement(FSNS(XML_a, XML_noFill), FSEND);
3511 else
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 ),
3529 XML_val, pVal,
3530 FSEND );
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 ),
3545 FSEND );
3548 namespace {
3550 const char* getErrorBarStyle(sal_Int32 nErrorBarStyle)
3552 switch(nErrorBarStyle)
3554 case cssc::ErrorBarStyle::NONE:
3555 return nullptr;
3556 case cssc::ErrorBarStyle::VARIANCE:
3557 break;
3558 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
3559 return "stdDev";
3560 case cssc::ErrorBarStyle::ABSOLUTE:
3561 return "fixedVal";
3562 case cssc::ErrorBarStyle::RELATIVE:
3563 return "percentage";
3564 case cssc::ErrorBarStyle::ERROR_MARGIN:
3565 break;
3566 case cssc::ErrorBarStyle::STANDARD_ERROR:
3567 return "stdErr";
3568 case cssc::ErrorBarStyle::FROM_DATA:
3569 return "cust";
3570 default:
3571 assert(false && "can't happen");
3573 return nullptr;
3576 Reference< chart2::data::XDataSequence> getLabeledSequence(
3577 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences,
3578 bool bPositive )
3580 OUString aDirection;
3581 if(bPositive)
3582 aDirection = "positive";
3583 else
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 );
3592 OUString aRole;
3593 if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) &&
3594 aRole.match( "error-bars" ) && aRole.indexOf(aDirection) >= 0 )
3596 return xSequence;
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);
3611 if(!pErrorBarStyle)
3612 return;
3614 FSHelperPtr pFS = GetFS();
3615 pFS->startElement( FSNS( XML_c, XML_errBars ),
3616 FSEND );
3617 pFS->singleElement( FSNS( XML_c, XML_errDir ),
3618 XML_val, bYError ? "y" : "x",
3619 FSEND );
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";
3626 else if(bPositive)
3627 pErrBarType = "plus";
3628 else if(bNegative)
3629 pErrBarType = "minus";
3630 else
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,
3638 FSEND );
3639 pFS->singleElement( FSNS( XML_c, XML_errValType ),
3640 XML_val, pErrorBarStyle,
3641 FSEND );
3642 pFS->singleElement( FSNS( XML_c, XML_noEndCap ),
3643 XML_val, "0",
3644 FSEND );
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();
3651 if(bPositive)
3653 exportSeriesValues(getLabeledSequence(aSequences, true), XML_plus);
3656 if(bNegative)
3658 exportSeriesValues(getLabeledSequence(aSequences, false), XML_minus);
3661 else
3663 double nVal = 0.0;
3664 if(nErrorBarStyle == cssc::ErrorBarStyle::STANDARD_DEVIATION)
3666 xErrorBarProps->getPropertyValue("Weight") >>= nVal;
3668 else
3670 if(bPositive)
3671 xErrorBarProps->getPropertyValue("PositiveError") >>= nVal;
3672 else
3673 xErrorBarProps->getPropertyValue("NegativeError") >>= nVal;
3676 OString aVal = OString::number(nVal);
3678 pFS->singleElement( FSNS( XML_c, XML_val ),
3679 XML_val, aVal.getStr(),
3680 FSEND );
3683 pFS->endElement( FSNS( XML_c, XML_errBars) );
3686 void ChartExport::exportView3D()
3688 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3689 if( !xPropSet.is() )
3690 return;
3691 FSHelperPtr pFS = GetFS();
3692 pFS->startElement( FSNS( XML_c, XML_view3D ),
3693 FSEND );
3694 sal_Int32 eChartType = getChartType( );
3695 // rotX
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])
3709 else
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 ),
3714 FSEND );
3716 // rotY
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 ),
3729 FSEND );
3731 else
3733 sal_Int32 nRotationY = 0;
3734 mAny >>= nRotationY;
3735 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
3736 if( nRotationY < 0 )
3737 nRotationY += 360;
3738 pFS->singleElement( FSNS( XML_c, XML_rotY ),
3739 XML_val, I32S( nRotationY ),
3740 FSEND );
3743 // rAngAx
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,
3751 FSEND );
3753 // perspective
3754 if( GetProperty( xPropSet, "Perspective" ) )
3756 sal_Int32 nPerspective = 0;
3757 mAny >>= nPerspective;
3758 // map Chart2 [0,100] to OOXML [0..200]
3759 nPerspective *= 2;
3760 pFS->singleElement( FSNS( XML_c, XML_perspective ),
3761 XML_val, I32S( nPerspective ),
3762 FSEND );
3764 pFS->endElement( FSNS( XML_c, XML_view3D ) );
3767 bool ChartExport::isDeep3dChart()
3769 bool isDeep = false;
3770 if( mbIs3DChart )
3772 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3773 if( GetProperty( xPropSet, "Deep" ) )
3774 mAny >>= isDeep;
3776 return isDeep;
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);
3788 if (!pSupplierObj)
3789 return aCode;
3791 SvNumberFormatter* pNumberFormatter = pSupplierObj->GetNumberFormatter();
3792 if (!pNumberFormatter)
3793 return aCode;
3795 SvNumberFormatter aTempFormatter( comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US);
3796 NfKeywordTable aKeywords;
3797 aTempFormatter.FillKeywordTableForExcel( aKeywords);
3798 aCode = pNumberFormatter->GetFormatStringForExcel( nKey, aKeywords, aTempFormatter);
3800 return aCode;
3803 }// drawingml
3804 }// oox
3806 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */