Branch libreoffice-5-0-4
[LibreOffice.git] / oox / source / export / chartexport.cxx
blob2f0853b935a391b8cc613b5510b31e45edd781af
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/tokens.hxx>
21 #include "oox/core/xmlfilterbase.hxx"
22 #include "oox/export/chartexport.hxx"
23 #include "oox/export/utils.hxx"
24 #include "drawingml/chart/typegroupconverter.hxx"
26 #include <cstdio>
28 #include <com/sun/star/awt/Gradient.hpp>
29 #include <com/sun/star/chart/XChartDocument.hpp>
30 #include <com/sun/star/chart/ChartLegendPosition.hpp>
31 #include <com/sun/star/chart/XTwoAxisXSupplier.hpp>
32 #include <com/sun/star/chart/XTwoAxisYSupplier.hpp>
33 #include <com/sun/star/chart/XAxisZSupplier.hpp>
34 #include <com/sun/star/chart/XChartDataArray.hpp>
35 #include <com/sun/star/chart/ChartDataRowSource.hpp>
36 #include <com/sun/star/chart/ChartAxisAssign.hpp>
37 #include <com/sun/star/chart/ChartSeriesAddress.hpp>
38 #include <com/sun/star/chart/X3DDisplay.hpp>
39 #include <com/sun/star/chart/XStatisticDisplay.hpp>
40 #include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
41 #include <com/sun/star/chart/ChartSymbolType.hpp>
42 #include <com/sun/star/chart/ChartAxisMarks.hpp>
43 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
44 #include <com/sun/star/chart/ChartAxisPosition.hpp>
45 #include <com/sun/star/chart/ChartSolidType.hpp>
46 #include <com/sun/star/chart/DataLabelPlacement.hpp>
47 #include <com/sun/star/chart/ErrorBarStyle.hpp>
48 #include <com/sun/star/chart/MissingValueTreatment.hpp>
50 #include <com/sun/star/chart2/XChartDocument.hpp>
51 #include <com/sun/star/chart2/XDiagram.hpp>
52 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
53 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
54 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
55 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
56 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
57 #include <com/sun/star/chart2/DataPointLabel.hpp>
58 #include <com/sun/star/chart2/Symbol.hpp>
59 #include <com/sun/star/chart2/data/XDataSource.hpp>
60 #include <com/sun/star/chart2/data/XDataSink.hpp>
61 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
62 #include <com/sun/star/chart2/data/XDataProvider.hpp>
63 #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
64 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
65 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
66 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
68 #include <com/sun/star/beans/XPropertySet.hpp>
69 #include <com/sun/star/beans/XPropertyState.hpp>
70 #include <com/sun/star/container/XEnumerationAccess.hpp>
71 #include <com/sun/star/drawing/XShape.hpp>
72 #include <com/sun/star/drawing/FillStyle.hpp>
73 #include <com/sun/star/drawing/BitmapMode.hpp>
74 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
75 #include <com/sun/star/lang/XServiceName.hpp>
77 #include <com/sun/star/table/CellAddress.hpp>
78 #include <com/sun/star/sheet/XFormulaParser.hpp>
79 #include <com/sun/star/sheet/XFormulaTokens.hpp>
80 #include <com/sun/star/sheet/FormulaToken.hpp>
81 #include <com/sun/star/sheet/AddressConvention.hpp>
83 #include <com/sun/star/text/WritingMode.hpp>
84 #include <com/sun/star/container/XNamed.hpp>
85 #include <com/sun/star/embed/XVisualObject.hpp>
86 #include <com/sun/star/embed/Aspects.hpp>
88 #include <comphelper/processfactory.hxx>
89 #include <comphelper/random.hxx>
90 #include <xmloff/SchXMLSeriesHelper.hxx>
91 #include "ColorPropertySet.hxx"
92 #include <set>
93 #include <unordered_set>
95 #include <rtl/math.hxx>
97 using namespace css;
98 using namespace css::uno;
99 using namespace css::drawing;
100 using namespace ::oox::core;
101 using css::beans::PropertyState;
102 using css::beans::PropertyValue;
103 using css::beans::XPropertySet;
104 using css::beans::XPropertyState;
105 using css::container::XEnumeration;
106 using css::container::XEnumerationAccess;
107 using css::container::XIndexAccess;
108 using css::container::XNamed;
109 using css::io::XOutputStream;
110 using css::table::CellAddress;
111 using css::sheet::XFormulaParser;
112 using css::sheet::XFormulaTokens;
113 using ::oox::core::XmlFilterBase;
114 using ::sax_fastparser::FSHelperPtr;
116 namespace cssc = css::chart;
118 namespace oox { namespace drawingml {
120 namespace {
122 sal_Int32 translateFromChart2AxisIndexToOox(sal_Int32 nIndex)
124 assert(nIndex == 0 || nIndex == 1);
125 if (nIndex == 1)
126 return AXIS_SECONDARY_Y;
127 return AXIS_PRIMARY_Y;
132 class lcl_MatchesRole : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool >
134 public:
135 explicit lcl_MatchesRole( const OUString & aRole ) :
136 m_aRole( aRole )
139 bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
141 if( !xSeq.is() )
142 return false;
143 Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
144 OUString aRole;
146 return ( xProp.is() &&
147 (xProp->getPropertyValue(
148 OUString( "Role" ) ) >>= aRole ) &&
149 m_aRole.equals( aRole ));
152 private:
153 OUString m_aRole;
156 template< typename T >
157 void lcl_SequenceToVectorAppend( const Sequence< T > & rSource, ::std::vector< T > & rDestination )
159 rDestination.reserve( rDestination.size() + rSource.getLength());
160 ::std::copy( rSource.begin(), rSource.end(),
161 ::std::back_inserter( rDestination ));
164 Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram )
166 Reference< chart2::data::XLabeledDataSequence > xResult;
169 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
170 xDiagram, uno::UNO_QUERY_THROW );
171 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
172 xCooSysCnt->getCoordinateSystems());
173 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
175 Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[i] );
176 OSL_ASSERT( xCooSys.is());
177 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
179 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
180 for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
182 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI );
183 OSL_ASSERT( xAxis.is());
184 if( xAxis.is())
186 chart2::ScaleData aScaleData = xAxis->getScaleData();
187 if( aScaleData.Categories.is())
189 xResult.set( aScaleData.Categories );
190 break;
197 catch( const uno::Exception & ex )
199 (void)ex; // avoid warning for pro build
200 OSL_FAIL( OUStringToOString(
201 "Exception caught. Type: " +
202 OUString::createFromAscii( typeid( ex ).name()) +
203 ", Message: " +
204 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
207 return xResult;
210 Reference< chart2::data::XDataSource > lcl_createDataSource(
211 const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData )
213 Reference< uno::XComponentContext > xContext(
214 comphelper::getProcessComponentContext() );
215 Reference< chart2::data::XDataSink > xSink(
216 xContext->getServiceManager()->createInstanceWithContext(
217 "com.sun.star.chart2.data.DataSource", xContext ),
218 uno::UNO_QUERY_THROW );
219 if( xSink.is())
220 xSink->setData( aData );
222 return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY );
225 Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc )
227 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer;
228 if( xChartDoc.is() )
230 Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
231 ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram ));
232 for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aSeriesIt( aSeriesVector.begin() )
233 ; aSeriesIt != aSeriesVector.end(); ++aSeriesIt )
235 Reference< chart2::data::XDataSource > xDataSource( *aSeriesIt, uno::UNO_QUERY );
236 if( !xDataSource.is() )
237 continue;
238 uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() );
239 lcl_SequenceToVectorAppend( aDataSequences, aContainer );
243 Sequence< Reference< chart2::data::XLabeledDataSequence > > aRet( aContainer.size());
244 ::std::copy( aContainer.begin(), aContainer.end(), aRet.getArray());
246 return aRet;
249 Reference< chart2::data::XLabeledDataSequence >
250 lcl_getDataSequenceByRole(
251 const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq,
252 const OUString & rRole )
254 Reference< chart2::data::XLabeledDataSequence > aNoResult;
256 const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
257 const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
258 const Reference< chart2::data::XLabeledDataSequence > * pMatch =
259 ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole ));
261 if( pMatch != pEnd )
262 return *pMatch;
264 return aNoResult;
267 Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, bool& rOutSourceHasCategoryLabels )
269 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector;
271 //categories are always the first sequence
272 Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
273 Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) );
274 if( xCategories.is() )
275 aLabeledSeqVector.push_back( xCategories );
276 rOutSourceHasCategoryLabels = xCategories.is();
278 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector(
279 lcl_getAllSeriesSequences( xChartDoc ) );
281 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
282 Reference< chart2::data::XLabeledDataSequence > xXValues(
283 lcl_getDataSequenceByRole( aSeriesSeqVector, OUString("values-x") ) );
284 if( xXValues.is() )
285 aLabeledSeqVector.push_back( xXValues );
287 //add all other sequences now without x-values
288 lcl_MatchesRole aHasXValues( OUString("values-x") );
289 for( sal_Int32 nN=0; nN<aSeriesSeqVector.getLength(); nN++ )
291 if( !aHasXValues( aSeriesSeqVector[nN] ) )
292 aLabeledSeqVector.push_back( aSeriesSeqVector[nN] );
295 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( aLabeledSeqVector.size() );
296 ::std::copy( aLabeledSeqVector.begin(), aLabeledSeqVector.end(), aSeq.getArray() );
298 return lcl_createDataSource( aSeq );
301 bool lcl_isSeriesAttachedToFirstAxis(
302 const Reference< chart2::XDataSeries > & xDataSeries )
304 bool bResult=true;
308 sal_Int32 nAxisIndex = 0;
309 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
310 if( xProp.is() )
311 xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex;
312 bResult = (0==nAxisIndex);
314 catch( const uno::Exception & ex )
316 (void)ex; // avoid warning for pro build
317 OSL_FAIL( OUStringToOString(
318 "Exception caught. Type: " +
319 OUString::createFromAscii( typeid( ex ).name()) +
320 ", Message: " +
321 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
324 return bResult;
327 OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
329 OUStringBuffer aResult;
330 bool bPrecedeWithSpace = false;
331 for( sal_Int32 nIndex=0; nIndex<rSequence.getLength(); ++nIndex )
333 if( !rSequence[nIndex].isEmpty())
335 if( bPrecedeWithSpace )
336 aResult.append( ' ' );
337 aResult.append( rSequence[nIndex] );
338 bPrecedeWithSpace = true;
341 return aResult.makeStringAndClear();
344 OUString lcl_getLabelString( const Reference< chart2::data::XDataSequence > & xLabelSeq )
346 Sequence< OUString > aLabels;
348 uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY );
349 if( xTextualDataSequence.is())
351 aLabels = xTextualDataSequence->getTextualData();
353 else if( xLabelSeq.is())
355 Sequence< uno::Any > aAnies( xLabelSeq->getData());
356 aLabels.realloc( aAnies.getLength());
357 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
358 aAnies[i] >>= aLabels[i];
361 return lcl_flattenStringSequence( aLabels );
364 void lcl_fillCategoriesIntoStringVector(
365 const Reference< chart2::data::XDataSequence > & xCategories,
366 ::std::vector< OUString > & rOutCategories )
368 OSL_ASSERT( xCategories.is());
369 if( !xCategories.is())
370 return;
371 Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xCategories, uno::UNO_QUERY );
372 if( xTextualDataSequence.is())
374 rOutCategories.clear();
375 Sequence< OUString > aTextData( xTextualDataSequence->getTextualData());
376 ::std::copy( aTextData.begin(), aTextData.end(),
377 ::std::back_inserter( rOutCategories ));
379 else
381 Sequence< uno::Any > aAnies( xCategories->getData());
382 rOutCategories.resize( aAnies.getLength());
383 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
384 aAnies[i] >>= rOutCategories[i];
388 ::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq )
390 double fNan = 0.0;
391 ::rtl::math::setNan( &fNan );
392 ::std::vector< double > aResult;
394 Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
395 if( xNumSeq.is())
397 Sequence< double > aValues( xNumSeq->getNumericalData());
398 ::std::copy( aValues.begin(), aValues.end(),
399 ::std::back_inserter( aResult ));
401 else if( xSeq.is())
403 Sequence< uno::Any > aAnies( xSeq->getData());
404 aResult.resize( aAnies.getLength(), fNan );
405 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
406 aAnies[i] >>= aResult[i];
408 return aResult;
411 sal_Int32 lcl_getChartType( const OUString& sChartType )
413 chart::TypeId eChartTypeId = chart::TYPEID_UNKNOWN;
414 if( sChartType == "com.sun.star.chart.BarDiagram"
415 || sChartType == "com.sun.star.chart2.ColumnChartType" )
416 eChartTypeId = chart::TYPEID_BAR;
417 else if( sChartType == "com.sun.star.chart.AreaDiagram"
418 || sChartType == "com.sun.star.chart2.AreaChartType" )
419 eChartTypeId = chart::TYPEID_AREA;
420 else if( sChartType == "com.sun.star.chart.LineDiagram"
421 || sChartType == "com.sun.star.chart2.LineChartType" )
422 eChartTypeId = chart::TYPEID_LINE;
423 else if( sChartType == "com.sun.star.chart.PieDiagram"
424 || sChartType == "com.sun.star.chart2.PieChartType" )
425 eChartTypeId = chart::TYPEID_PIE;
426 else if( sChartType == "com.sun.star.chart.DonutDiagram"
427 || sChartType == "com.sun.star.chart2.DonutChartType" )
428 eChartTypeId = chart::TYPEID_DOUGHNUT;
429 else if( sChartType == "com.sun.star.chart.XYDiagram"
430 || sChartType == "com.sun.star.chart2.ScatterChartType" )
431 eChartTypeId = chart::TYPEID_SCATTER;
432 else if( sChartType == "com.sun.star.chart.NetDiagram"
433 || sChartType == "com.sun.star.chart2.NetChartType" )
434 eChartTypeId = chart::TYPEID_RADARLINE;
435 else if( sChartType == "com.sun.star.chart.FilledNetDiagram"
436 || sChartType == "com.sun.star.chart2.FilledNetChartType" )
437 eChartTypeId = chart::TYPEID_RADARAREA;
438 else if( sChartType == "com.sun.star.chart.StockDiagram"
439 || sChartType == "com.sun.star.chart2.CandleStickChartType" )
440 eChartTypeId = chart::TYPEID_STOCK;
441 else if( sChartType == "com.sun.star.chart.BubbleDiagram"
442 || sChartType == "com.sun.star.chart2.BubbleChartType" )
443 eChartTypeId = chart::TYPEID_BUBBLE;
445 return eChartTypeId;
448 sal_Int32 lcl_generateRandomValue()
450 return comphelper::rng::uniform_int_distribution(0, 100000000-1);
453 ChartExport::ChartExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, Reference< frame::XModel >& xModel, XmlFilterBase* pFB, DocumentType eDocumentType )
454 : DrawingML( pFS, pFB, eDocumentType )
455 , mnXmlNamespace( nXmlNamespace )
456 , mnSeriesCount(0)
457 , mxChartModel( xModel )
458 , mbHasCategoryLabels( false )
459 , mbHasZAxis( false )
460 , mbIs3DChart( false )
461 , mbStacked(false)
462 , mbPercent(false)
466 sal_Int32 ChartExport::GetChartID( )
468 sal_Int32 nID = GetFB()->GetUniqueId();
469 return nID;
472 sal_Int32 ChartExport::getChartType( )
474 OUString sChartType = mxDiagram->getDiagramType();
475 return lcl_getChartType( sChartType );
478 OUString ChartExport::parseFormula( const OUString& rRange )
480 OUString aResult;
481 Reference< XFormulaParser > xParser;
482 uno::Reference< lang::XMultiServiceFactory > xSF( GetFB()->getModelFactory(), uno::UNO_QUERY );
483 if( xSF.is() )
487 xParser.set( xSF->createInstance("com.sun.star.sheet.FormulaParser"), UNO_QUERY );
489 catch( Exception& )
494 SAL_WARN_IF(!xParser.is(), "oox", "creating formula parser failed");
496 if( xParser.is() )
498 Reference< XPropertySet > xParserProps( xParser, uno::UNO_QUERY );
499 if( xParserProps.is() )
501 xParserProps->setPropertyValue("FormulaConvention", uno::makeAny(css::sheet::AddressConvention::OOO) );
503 uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( rRange, CellAddress( 0, 0, 0 ) );
504 if( xParserProps.is() )
506 xParserProps->setPropertyValue("FormulaConvention", uno::makeAny(css::sheet::AddressConvention::XL_OOX) );
508 aResult = xParser->printFormula( aTokens, CellAddress( 0, 0, 0 ) );
510 else
512 //FIXME: currently just using simple converter, e.g $Sheet1.$A$1:$C$1 -> Sheet1!$A$1:$C$1
513 OUString aRange( rRange );
514 if( aRange.startsWith("$") )
515 aRange = aRange.copy(1);
516 aRange = aRange.replaceAll(".$", "!$" );
517 aResult = aRange;
520 return aResult;
523 ChartExport& ChartExport::WriteChartObj( const Reference< XShape >& xShape, sal_Int32 nChartCount )
525 FSHelperPtr pFS = GetFS();
527 pFS->startElementNS( mnXmlNamespace, XML_graphicFrame, FSEND );
529 pFS->startElementNS( mnXmlNamespace, XML_nvGraphicFramePr, FSEND );
531 // TODO: get the correct chart name chart id
532 OUString sName = "Object 1";
533 Reference< XNamed > xNamed( xShape, UNO_QUERY );
534 if (xNamed.is())
535 sName = xNamed->getName();
537 sal_Int32 nID = GetChartID();
539 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
540 XML_id, I32S( nID ),
541 XML_name, USS( sName ),
542 FSEND );
544 pFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr,
545 FSEND );
547 if( GetDocumentType() == DOCUMENT_PPTX )
548 pFS->singleElementNS( mnXmlNamespace, XML_nvPr,
549 FSEND );
550 pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
552 // visual chart properties
553 WriteShapeTransformation( xShape, mnXmlNamespace );
555 // writer chart object
556 pFS->startElement( FSNS( XML_a, XML_graphic ), FSEND );
557 pFS->startElement( FSNS( XML_a, XML_graphicData ),
558 XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart",
559 FSEND );
560 OUString sId;
561 const char* sFullPath = NULL;
562 const char* sRelativePath = NULL;
563 switch( GetDocumentType() )
565 case DOCUMENT_DOCX:
567 sFullPath = "word/charts/chart";
568 sRelativePath = "charts/chart";
569 break;
571 case DOCUMENT_PPTX:
573 sFullPath = "ppt/charts/chart";
574 sRelativePath = "../charts/chart";
575 break;
577 case DOCUMENT_XLSX:
579 sFullPath = "xl/charts/chart";
580 sRelativePath = "../charts/chart";
581 break;
583 default:
585 sFullPath = "charts/chart";
586 sRelativePath = "charts/chart";
587 break;
590 OUString sFullStream = OUStringBuffer()
591 .appendAscii(sFullPath)
592 .append(nChartCount)
593 .appendAscii( ".xml" )
594 .makeStringAndClear();
595 OUString sRelativeStream = OUStringBuffer()
596 .appendAscii(sRelativePath)
597 .append(nChartCount)
598 .appendAscii( ".xml" )
599 .makeStringAndClear();
600 FSHelperPtr pChart = CreateOutputStream(
601 sFullStream,
602 sRelativeStream,
603 pFS->getOutputStream(),
604 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
605 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
606 &sId );
608 pFS->singleElement( FSNS( XML_c, XML_chart ),
609 FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart",
610 FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
611 FSNS( XML_r, XML_id ), USS( sId ),
612 FSEND );
614 pFS->endElement( FSNS( XML_a, XML_graphicData ) );
615 pFS->endElement( FSNS( XML_a, XML_graphic ) );
616 pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
618 SetFS( pChart );
619 ExportContent();
621 return *this;
624 void ChartExport::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc )
626 if( xChartDoc.is())
629 Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
630 OSL_ENSURE( xDataProvider.is(), "No DataProvider" );
631 if( xDataProvider.is())
633 Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels ));
634 Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource ));
635 OUString sCellRange, sBrokenRange;
636 bool bBrokenRangeAvailable = false;
637 for( sal_Int32 i=0; i<aArgs.getLength(); ++i )
639 if ( aArgs[i].Name == "CellRangeRepresentation" )
640 aArgs[i].Value >>= sCellRange;
641 else if ( aArgs[i].Name == "BrokenCellRangeForExport" )
643 if( aArgs[i].Value >>= sBrokenRange )
644 bBrokenRangeAvailable = true;
646 else if ( aArgs[i].Name == "SequenceMapping" )
647 aArgs[i].Value >>= maSequenceMapping;
650 // #i79009# For Writer we have to export a broken version of the
651 // range, where every row number is noe too large, so that older
652 // version can correctly read those files.
653 msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange);
654 if( !msChartAddress.isEmpty() )
656 // convert format to XML-conform one
657 Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY );
658 if( xConversion.is())
659 msChartAddress = xConversion->convertRangeToXML( msChartAddress );
663 catch( const uno::Exception & ex )
665 (void)ex; // avoid warning for pro build
666 OSL_FAIL( OUStringToOString(
667 "Exception caught. Type: " +
668 OUString::createFromAscii( typeid( ex ).name()) +
669 ", Message: " +
670 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
674 void ChartExport::ExportContent()
676 Reference< chart2::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
677 OSL_ASSERT( xChartDoc.is() );
678 if( !xChartDoc.is() )
679 return;
680 InitRangeSegmentationProperties( xChartDoc );
681 // TODO: export chart
682 _ExportContent( );
685 void ChartExport::_ExportContent()
687 Reference< css::chart::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
688 if( xChartDoc.is())
690 // determine if data comes from the outside
691 bool bIncludeTable = true;
693 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
694 if( xNewDoc.is())
696 // check if we have own data. If so we must not export the complete
697 // range string, as this is our only indicator for having own or
698 // external data. @todo: fix this in the file format!
699 Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
700 if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
702 bIncludeTable = false;
705 else
707 Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY );
708 if( xServ.is())
710 if( xServ->supportsService(
711 OUString("com.sun.star.chart.ChartTableAddressSupplier")))
713 Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY );
714 if( xProp.is())
716 Any aAny;
719 OUString sChartAddress;
720 aAny = xProp->getPropertyValue(
721 OUString("ChartRangeAddress"));
722 aAny >>= msChartAddress;
723 //maExportHelper.SetChartRangeAddress( sChartAddress );
725 //maExportHelper.SetTableNumberList( sTableNumberList );
727 // do not include own table if there are external addresses
728 bIncludeTable = sChartAddress.isEmpty();
730 catch( beans::UnknownPropertyException & )
732 OSL_FAIL( "Property ChartRangeAddress not supported by ChartDocument" );
738 exportChartSpace( xChartDoc, bIncludeTable );
740 else
742 OSL_FAIL( "Couldn't export chart due to wrong XModel" );
746 void ChartExport::exportChartSpace( Reference< css::chart::XChartDocument > xChartDoc,
747 bool bIncludeTable )
749 FSHelperPtr pFS = GetFS();
750 pFS->startElement( FSNS( XML_c, XML_chartSpace ),
751 FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart",
752 FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main",
753 FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
754 FSEND );
755 // TODO: get the correct editing lanauge
756 pFS->singleElement( FSNS( XML_c, XML_lang ),
757 XML_val, "en-US",
758 FSEND );
760 pFS->singleElement(FSNS( XML_c, XML_roundedCorners),
761 XML_val, "0",
762 FSEND);
764 if( !bIncludeTable )
766 // TODO:external data
768 //XML_chart
769 exportChart(xChartDoc);
771 // TODO: printSettings
772 // TODO: style
773 // TODO: text properties
774 // TODO: shape properties
775 Reference< XPropertySet > xPropSet( xChartDoc->getArea(), uno::UNO_QUERY );
776 if( xPropSet.is() )
777 exportShapeProps( xPropSet );
779 //XML_externalData
780 exportExternalData(xChartDoc);
782 pFS->endElement( FSNS( XML_c, XML_chartSpace ) );
785 void ChartExport::exportExternalData( Reference< css::chart::XChartDocument > xChartDoc )
787 // Embedded external data is grab bagged for docx file hence adding export part of
788 // external data for docx files only.
789 if(GetDocumentType() != DOCUMENT_DOCX)
790 return;
792 OUString externalDataPath;
793 Reference< beans::XPropertySet > xDocPropSet( xChartDoc->getDiagram(), uno::UNO_QUERY );
794 if( xDocPropSet.is())
798 Any aAny( xDocPropSet->getPropertyValue(
799 OUString( "ExternalData" )));
800 aAny >>= externalDataPath;
802 catch( beans::UnknownPropertyException & )
804 SAL_WARN("oox", "Required property not found in ChartDocument");
807 if(!externalDataPath.isEmpty())
809 // Here adding external data entry to relationship.
810 OUString relationPath = externalDataPath;
811 // Converting absolute path to relative path.
812 if( externalDataPath[ 0 ] != '.' && externalDataPath[ 1 ] != '.')
814 sal_Int32 nStartPos = 0;
815 sal_Int32 nSepPos = externalDataPath.indexOf( '/', nStartPos );
816 if( nSepPos > 0)
818 relationPath = relationPath.copy( nSepPos, ::std::max< sal_Int32 >( externalDataPath.getLength(), 0 ) - nSepPos );
819 relationPath = OUStringBuffer( ".." ).append( relationPath ).makeStringAndClear();
822 FSHelperPtr pFS = GetFS();
823 OUString type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
824 if (relationPath.endsWith(OUString(".bin")))
825 type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
827 OUString sRelId = GetFB()->addRelation(pFS->getOutputStream(),
828 type,
829 relationPath);
830 pFS->singleElementNS( XML_c, XML_externalData,
831 FSNS(XML_r, XML_id), OUStringToOString(sRelId, RTL_TEXTENCODING_UTF8),
832 FSEND);
836 void ChartExport::exportChart( Reference< css::chart::XChartDocument > xChartDoc )
838 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
839 mxDiagram.set( xChartDoc->getDiagram() );
840 if( xNewDoc.is())
841 mxNewDiagram.set( xNewDoc->getFirstDiagram());
843 // get Properties of ChartDocument
844 bool bHasMainTitle = false;
845 bool bHasSubTitle = false;
846 bool bHasLegend = false;
847 Reference< beans::XPropertySet > xDocPropSet( xChartDoc, uno::UNO_QUERY );
848 if( xDocPropSet.is())
852 Any aAny( xDocPropSet->getPropertyValue(
853 OUString( "HasMainTitle" )));
854 aAny >>= bHasMainTitle;
855 aAny = xDocPropSet->getPropertyValue(
856 OUString( "HasSubTitle" ));
857 aAny >>= bHasSubTitle;
858 aAny = xDocPropSet->getPropertyValue(
859 OUString( "HasLegend" ));
860 aAny >>= bHasLegend;
862 catch( beans::UnknownPropertyException & )
864 SAL_WARN("oox", "Required property not found in ChartDocument");
866 } // if( xDocPropSet.is())
868 // chart element
870 FSHelperPtr pFS = GetFS();
871 pFS->startElement( FSNS( XML_c, XML_chart ),
872 FSEND );
874 // title
875 if( bHasMainTitle )
877 Reference< drawing::XShape > xShape = xChartDoc->getTitle();
878 if( xShape.is() )
880 exportTitle( xShape );
881 pFS->singleElement( FSNS(XML_c, XML_autoTitleDeleted),
882 XML_val, "0",
883 FSEND);
886 InitPlotArea( );
887 if( mbIs3DChart )
889 exportView3D();
891 // floor
892 Reference< beans::XPropertySet > xFloor( mxNewDiagram->getFloor(), uno::UNO_QUERY );
893 if( xFloor.is() )
895 pFS->startElement( FSNS( XML_c, XML_floor ),
896 FSEND );
897 exportShapeProps( xFloor );
898 pFS->endElement( FSNS( XML_c, XML_floor ) );
901 // sideWall
903 // backWall
904 Reference< beans::XPropertySet > xBackWall( mxNewDiagram->getWall(), uno::UNO_QUERY );
905 if( xBackWall.is() )
907 pFS->startElement( FSNS( XML_c, XML_backWall ),
908 FSEND );
909 exportShapeProps( xBackWall );
910 pFS->endElement( FSNS( XML_c, XML_backWall ) );
914 // plot area
915 exportPlotArea( );
916 // legend
917 if( bHasLegend )
918 exportLegend( xChartDoc );
920 uno::Reference<beans::XPropertySet> xDiagramPropSet(xChartDoc->getDiagram(), uno::UNO_QUERY);
921 uno::Any aPlotVisOnly = xDiagramPropSet->getPropertyValue("IncludeHiddenCells");
922 bool bIncludeHiddenCells = false;
923 aPlotVisOnly >>= bIncludeHiddenCells;
924 pFS->singleElement( FSNS( XML_c, XML_plotVisOnly ),
925 XML_val, BS(!bIncludeHiddenCells),
926 FSEND );
928 exportMissingValueTreatment(Reference<beans::XPropertySet>(mxDiagram, uno::UNO_QUERY));
930 pFS->endElement( FSNS( XML_c, XML_chart ) );
933 void ChartExport::exportMissingValueTreatment(uno::Reference<beans::XPropertySet> xPropSet)
935 if (!xPropSet.is())
936 return;
938 sal_Int32 nVal = 0;
939 uno::Any aAny = xPropSet->getPropertyValue("MissingValueTreatment");
940 if (!(aAny >>= nVal))
941 return;
943 const char* pVal = NULL;
944 switch (nVal)
946 case cssc::MissingValueTreatment::LEAVE_GAP:
947 pVal = "gap";
948 break;
949 case cssc::MissingValueTreatment::USE_ZERO:
950 pVal = "zero";
951 break;
952 case cssc::MissingValueTreatment::CONTINUE:
953 pVal = "span";
954 break;
955 default:
956 SAL_WARN("oox", "unknown MissingValueTreatment value");
957 break;
960 FSHelperPtr pFS = GetFS();
961 pFS->singleElement( FSNS(XML_c, XML_dispBlanksAs),
962 XML_val, pVal,
963 FSEND);
966 void ChartExport::exportLegend( Reference< css::chart::XChartDocument > xChartDoc )
968 FSHelperPtr pFS = GetFS();
969 pFS->startElement( FSNS( XML_c, XML_legend ),
970 FSEND );
972 Reference< beans::XPropertySet > xProp( xChartDoc->getLegend(), uno::UNO_QUERY );
973 if( xProp.is() )
975 // position
976 css::chart::ChartLegendPosition aLegendPos = css::chart::ChartLegendPosition_NONE;
979 Any aAny( xProp->getPropertyValue(
980 OUString( "Alignment" )));
981 aAny >>= aLegendPos;
983 catch( beans::UnknownPropertyException & )
985 SAL_WARN("oox", "Property Align not found in ChartLegend");
988 const char* strPos = NULL;
989 switch( aLegendPos )
991 case css::chart::ChartLegendPosition_LEFT:
992 strPos = "l";
993 break;
994 case css::chart::ChartLegendPosition_RIGHT:
995 strPos = "r";
996 break;
997 case css::chart::ChartLegendPosition_TOP:
998 strPos = "t";
999 break;
1000 case css::chart::ChartLegendPosition_BOTTOM:
1001 strPos = "b";
1002 break;
1003 case css::chart::ChartLegendPosition_NONE:
1004 case css::chart::ChartLegendPosition_MAKE_FIXED_SIZE:
1005 // nothing
1006 break;
1009 if( strPos != NULL )
1011 pFS->singleElement( FSNS( XML_c, XML_legendPos ),
1012 XML_val, strPos,
1013 FSEND );
1016 uno::Any aRelativePos = xProp->getPropertyValue("RelativePosition");
1017 if (aRelativePos.hasValue())
1019 chart2::RelativePosition aPos = aRelativePos.get<chart2::RelativePosition>();
1020 pFS->startElement(FSNS(XML_c, XML_layout), FSEND);
1021 pFS->startElement(FSNS(XML_c, XML_manualLayout), FSEND);
1023 pFS->singleElement(FSNS(XML_c, XML_xMode),
1024 XML_val, "edge",
1025 FSEND);
1026 pFS->singleElement(FSNS(XML_c, XML_yMode),
1027 XML_val, "edge",
1028 FSEND);
1030 double x = aPos.Primary;
1031 double y = aPos.Secondary;
1033 pFS->singleElement(FSNS(XML_c, XML_x),
1034 XML_val, IS(x),
1035 FSEND);
1036 pFS->singleElement(FSNS(XML_c, XML_y),
1037 XML_val, IS(y),
1038 FSEND);
1039 SAL_WARN_IF(aPos.Anchor != 0, "oox.chart", "unsupported anchor position");
1041 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1042 pFS->endElement(FSNS(XML_c, XML_layout));
1045 if (strPos != NULL)
1047 pFS->singleElement( FSNS( XML_c, XML_overlay ),
1048 XML_val, "0",
1049 FSEND );
1052 // shape properties
1053 exportShapeProps( xProp );
1056 // legendEntry
1058 pFS->endElement( FSNS( XML_c, XML_legend ) );
1061 namespace {
1064 * nRotation is a 100th of a degree and the return value is
1065 * in a 60,000th of a degree
1067 * Also rotation is in opposite directions so multiply with -1
1069 OString calcRotationValue(sal_Int32 nRotation)
1071 if (nRotation > 18000) // 180 degree
1073 nRotation -= 36000;
1075 nRotation *= -600;
1076 return OString::number(nRotation);
1081 void ChartExport::exportTitle( Reference< XShape > xShape )
1083 OUString sText;
1084 Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1085 if( xPropSet.is())
1087 xPropSet->getPropertyValue("String") >>= sText;
1089 if( sText.isEmpty() )
1090 return;
1092 FSHelperPtr pFS = GetFS();
1093 pFS->startElement( FSNS( XML_c, XML_title ),
1094 FSEND );
1096 pFS->startElement( FSNS( XML_c, XML_tx ),
1097 FSEND );
1098 pFS->startElement( FSNS( XML_c, XML_rich ),
1099 FSEND );
1101 // TODO: bodyPr
1102 const char* sWritingMode = NULL;
1103 bool bVertical = false;
1104 xPropSet->getPropertyValue("StackedText") >>= bVertical;
1105 if( bVertical )
1106 sWritingMode = "wordArtVert";
1108 sal_Int32 nRotation = 0;
1109 xPropSet->getPropertyValue("TextRotation") >>= nRotation;
1111 pFS->singleElement( FSNS( XML_a, XML_bodyPr ),
1112 XML_vert, sWritingMode,
1113 XML_rot, nRotation == 0 ? NULL : calcRotationValue(nRotation).getStr(),
1114 FSEND );
1115 // TODO: lstStyle
1116 pFS->singleElement( FSNS( XML_a, XML_lstStyle ),
1117 FSEND );
1118 // FIXME: handle multipul paragraphs to parse aText
1119 pFS->startElement( FSNS( XML_a, XML_p ),
1120 FSEND );
1122 pFS->startElement( FSNS( XML_a, XML_pPr ),
1123 FSEND );
1125 WriteRunProperties(xPropSet, false, XML_defRPr);
1127 pFS->endElement( FSNS( XML_a, XML_pPr ) );
1129 pFS->startElement( FSNS( XML_a, XML_r ),
1130 FSEND );
1131 WriteRunProperties( xPropSet, false );
1132 pFS->startElement( FSNS( XML_a, XML_t ),
1133 FSEND );
1134 pFS->writeEscaped( sText );
1135 pFS->endElement( FSNS( XML_a, XML_t ) );
1136 pFS->endElement( FSNS( XML_a, XML_r ) );
1138 pFS->endElement( FSNS( XML_a, XML_p ) );
1140 pFS->endElement( FSNS( XML_c, XML_rich ) );
1141 pFS->endElement( FSNS( XML_c, XML_tx ) );
1143 uno::Any aManualLayout = xPropSet->getPropertyValue("RelativePosition");
1144 if (aManualLayout.hasValue())
1146 pFS->startElement(FSNS( XML_c, XML_layout ), FSEND);
1147 pFS->startElement(FSNS(XML_c, XML_manualLayout), FSEND);
1148 pFS->singleElement(FSNS(XML_c, XML_xMode),
1149 XML_val, "edge",
1150 FSEND);
1151 pFS->singleElement(FSNS(XML_c, XML_yMode),
1152 XML_val, "edge",
1153 FSEND);
1155 Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1156 awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1158 // awt::Size aSize = xShape->getSize();
1159 awt::Point aPos2 = xShape->getPosition();
1160 double x = (double)aPos2.X / (double) aPageSize.Width;
1161 double y = (double)aPos2.Y / (double) aPageSize.Height;
1163 pFS->singleElement(FSNS(XML_c, XML_wMode),
1164 XML_val, "edge",
1165 FSEND);
1166 pFS->singleElement(FSNS(XML_c, XML_hMode),
1167 XML_val, "edge",
1168 FSEND);
1170 pFS->singleElement(FSNS(XML_c, XML_x),
1171 XML_val, IS(x),
1172 FSEND);
1173 pFS->singleElement(FSNS(XML_c, XML_y),
1174 XML_val, IS(y),
1175 FSEND);
1177 pFS->singleElement(FSNS(XML_c, XML_w),
1178 XML_val, "",
1179 FSEND);
1180 pFS->singleElement(FSNS(XML_c, XML_h),
1181 XML_val, "",
1182 FSEND);
1184 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1185 pFS->endElement(FSNS(XML_c, XML_layout));
1188 pFS->singleElement( FSNS(XML_c, XML_overlay),
1189 XML_val, "0",
1190 FSEND);
1192 pFS->endElement( FSNS( XML_c, XML_title ) );
1195 void ChartExport::exportPlotArea( )
1197 Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( mxNewDiagram, uno::UNO_QUERY );
1198 if( ! xBCooSysCnt.is())
1199 return;
1201 // plot-area element
1203 FSHelperPtr pFS = GetFS();
1204 pFS->startElement( FSNS( XML_c, XML_plotArea ),
1205 FSEND );
1207 Reference<beans::XPropertySet> xWall(mxNewDiagram, uno::UNO_QUERY);
1208 if( xWall.is() )
1210 uno::Any aAny = xWall->getPropertyValue("RelativePosition");
1211 if (aAny.hasValue())
1213 chart2::RelativePosition aPos = aAny.get<chart2::RelativePosition>();
1214 aAny = xWall->getPropertyValue("RelativeSize");
1215 chart2::RelativeSize aSize = aAny.get<chart2::RelativeSize>();
1216 exportManualLayout(aPos, aSize);
1220 // chart type
1221 Sequence< Reference< chart2::XCoordinateSystem > >
1222 aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
1223 for( sal_Int32 nCSIdx=0; nCSIdx<aCooSysSeq.getLength(); ++nCSIdx )
1226 Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCSIdx], uno::UNO_QUERY );
1227 if( ! xCTCnt.is())
1228 continue;
1229 mnSeriesCount=0;
1230 Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
1231 for( sal_Int32 nCTIdx=0; nCTIdx<aCTSeq.getLength(); ++nCTIdx )
1233 Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nCTIdx], uno::UNO_QUERY );
1234 if( ! xDSCnt.is())
1235 return;
1236 Reference< chart2::XChartType > xChartType( aCTSeq[nCTIdx], uno::UNO_QUERY );
1237 if( ! xChartType.is())
1238 continue;
1239 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
1240 OUString aChartType( xChartType->getChartType());
1241 sal_Int32 eChartType = lcl_getChartType( aChartType );
1242 switch( eChartType )
1244 case chart::TYPEID_BAR:
1246 exportBarChart( xChartType );
1247 break;
1249 case chart::TYPEID_AREA:
1251 exportAreaChart( xChartType );
1252 break;
1254 case chart::TYPEID_LINE:
1256 exportLineChart( xChartType );
1257 break;
1259 case chart::TYPEID_BUBBLE:
1261 exportBubbleChart( xChartType );
1262 break;
1264 case chart::TYPEID_OFPIE:
1266 break;
1268 case chart::TYPEID_DOUGHNUT:
1269 case chart::TYPEID_PIE:
1271 exportPieChart( xChartType );
1272 break;
1274 case chart::TYPEID_RADARLINE:
1275 case chart::TYPEID_RADARAREA:
1277 exportRadarChart( xChartType );
1278 break;
1280 case chart::TYPEID_SCATTER:
1282 exportScatterChart( xChartType );
1283 break;
1285 case chart::TYPEID_STOCK:
1287 exportStockChart( xChartType );
1288 break;
1290 case chart::TYPEID_SURFACE:
1292 exportSurfaceChart( xChartType );
1293 break;
1295 default:
1297 SAL_WARN("oox", "ChartExport::exportPlotArea -- not support chart type");
1298 break;
1304 //Axis Data
1305 exportAxes( );
1306 // Data Table
1307 exportDataTable();
1309 // shape properties
1311 * Export the Plot area Shape Properties
1312 * eg: Fill and Outline
1314 Reference< css::chart::X3DDisplay > xWallFloorSupplier( mxDiagram, uno::UNO_QUERY );
1315 if( xWallFloorSupplier.is() )
1317 Reference< beans::XPropertySet > xWallPropSet( xWallFloorSupplier->getWall(), uno::UNO_QUERY );
1318 if( xWallPropSet.is() )
1320 exportPlotAreaShapeProps( xWallPropSet );
1324 pFS->endElement( FSNS( XML_c, XML_plotArea ) );
1328 void ChartExport::exportManualLayout(const css::chart2::RelativePosition& rPos, const css::chart2::RelativeSize& rSize)
1330 FSHelperPtr pFS = GetFS();
1331 pFS->startElement(FSNS(XML_c, XML_layout), FSEND);
1332 pFS->startElement(FSNS(XML_c, XML_manualLayout), FSEND);
1333 pFS->singleElement(FSNS(XML_c, XML_layoutTarget),
1334 XML_val, "inner",
1335 FSEND);
1336 pFS->singleElement(FSNS(XML_c, XML_xMode),
1337 XML_val, "edge",
1338 FSEND);
1339 pFS->singleElement(FSNS(XML_c, XML_yMode),
1340 XML_val, "edge",
1341 FSEND);
1343 double x = rPos.Primary;
1344 double y = rPos.Secondary;
1345 double w = rSize.Primary;
1346 double h = rSize.Secondary;
1347 switch (rPos.Anchor)
1349 case drawing::Alignment_LEFT:
1350 y -= (h/2);
1351 break;
1352 case drawing::Alignment_TOP_LEFT:
1353 break;
1354 case drawing::Alignment_BOTTOM_LEFT:
1355 y -= h;
1356 break;
1357 case drawing::Alignment_TOP:
1358 x -= (w/2);
1359 break;
1360 case drawing::Alignment_CENTER:
1361 x -= (w/2);
1362 y -= (h/2);
1363 break;
1364 case drawing::Alignment_BOTTOM:
1365 x -= (w/2);
1366 y -= h;
1367 break;
1368 case drawing::Alignment_TOP_RIGHT:
1369 x -= w;
1370 break;
1371 case drawing::Alignment_BOTTOM_RIGHT:
1372 x -= w;
1373 y -= h;
1374 break;
1375 case drawing::Alignment_RIGHT:
1376 y -= (h/2);
1377 x -= w;
1378 break;
1379 default:
1380 SAL_WARN("oox.chart", "unhandled alignment case for manual layout export");
1383 pFS->singleElement(FSNS(XML_c, XML_x),
1384 XML_val, IS(x),
1385 FSEND);
1387 pFS->singleElement(FSNS(XML_c, XML_y),
1388 XML_val, IS(y),
1389 FSEND);
1391 pFS->singleElement(FSNS(XML_c, XML_w),
1392 XML_val, IS(w),
1393 FSEND);
1395 pFS->singleElement(FSNS(XML_c, XML_h),
1396 XML_val, IS(h),
1397 FSEND);
1399 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1400 pFS->endElement(FSNS(XML_c, XML_layout));
1403 void ChartExport::exportPlotAreaShapeProps( Reference< XPropertySet > xPropSet )
1405 FSHelperPtr pFS = GetFS();
1406 pFS->startElement( FSNS( XML_c, XML_spPr ),
1407 FSEND );
1409 exportFill( xPropSet );
1410 WriteOutline( xPropSet );
1412 pFS->endElement( FSNS( XML_c, XML_spPr ) );
1415 void ChartExport::exportFill( Reference< XPropertySet > xPropSet )
1417 if ( !GetProperty( xPropSet, "FillStyle" ) )
1418 return;
1419 FillStyle aFillStyle( FillStyle_NONE );
1420 xPropSet->getPropertyValue( "FillStyle" ) >>= aFillStyle;
1421 switch( aFillStyle )
1423 case FillStyle_GRADIENT :
1424 exportGradientFill( xPropSet );
1425 break;
1426 case FillStyle_BITMAP :
1427 exportBitmapFill( xPropSet );
1428 break;
1429 default:
1430 WriteFill( xPropSet );
1434 void ChartExport::exportBitmapFill( Reference< XPropertySet > xPropSet )
1436 if( xPropSet.is() )
1438 OUString sFillBitmapName;
1439 xPropSet->getPropertyValue("FillBitmapName") >>= sFillBitmapName;
1441 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1444 uno::Reference< container::XNameAccess > xBitmap( xFact->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY );
1445 uno::Any rValue = xBitmap->getByName( sFillBitmapName );
1446 OUString sBitmapURL;
1447 if( (rValue >>= sBitmapURL) )
1449 WriteBlipFill( xPropSet, sBitmapURL, XML_a, true, true );
1452 catch (const uno::Exception & rEx)
1454 SAL_INFO("oox", "ChartExport::exportBitmapFill " << rEx.Message);
1460 void ChartExport::exportGradientFill( Reference< XPropertySet > xPropSet )
1462 if( xPropSet.is() )
1464 OUString sFillGradientName;
1465 xPropSet->getPropertyValue("FillGradientName") >>= sFillGradientName;
1467 awt::Gradient aGradient;
1468 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1471 uno::Reference< container::XNameAccess > xGradient( xFact->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY );
1472 uno::Any rValue = xGradient->getByName( sFillGradientName );
1473 if( (rValue >>= aGradient) )
1475 mpFS->startElementNS( XML_a, XML_gradFill, FSEND );
1476 WriteGradientFill( aGradient );
1477 mpFS->endElementNS( XML_a, XML_gradFill );
1480 catch (const uno::Exception & rEx)
1482 SAL_INFO("oox",
1483 "ChartExport::exportGradientFill " << rEx.Message);
1489 void ChartExport::exportDataTable( )
1491 FSHelperPtr pFS = GetFS();
1492 Reference< beans::XPropertySet > aPropSet( mxDiagram, uno::UNO_QUERY );
1494 bool bShowVBorder = false;
1495 bool bShowHBorder = false;
1496 bool bShowOutline = false;
1498 if (GetProperty( aPropSet, "DataTableHBorder"))
1499 mAny >>= bShowHBorder;
1500 if (GetProperty( aPropSet, "DataTableVBorder"))
1501 mAny >>= bShowVBorder;
1502 if (GetProperty( aPropSet, "DataTableOutline"))
1503 mAny >>= bShowOutline;
1505 if (bShowVBorder || bShowHBorder || bShowOutline)
1507 pFS->startElement( FSNS( XML_c, XML_dTable),
1508 FSEND );
1509 if (bShowHBorder)
1510 pFS->singleElement( FSNS( XML_c, XML_showHorzBorder ),
1511 XML_val, "1",
1512 FSEND );
1513 if (bShowVBorder)
1514 pFS->singleElement( FSNS( XML_c, XML_showVertBorder ),
1515 XML_val, "1",
1516 FSEND );
1517 if (bShowOutline)
1518 pFS->singleElement( FSNS( XML_c, XML_showOutline ),
1519 XML_val, "1",
1520 FSEND );
1522 pFS->endElement( FSNS( XML_c, XML_dTable));
1526 void ChartExport::exportAreaChart( Reference< chart2::XChartType > xChartType )
1528 FSHelperPtr pFS = GetFS();
1529 sal_Int32 nTypeId = XML_areaChart;
1530 if( mbIs3DChart )
1531 nTypeId = XML_area3DChart;
1532 pFS->startElement( FSNS( XML_c, nTypeId ),
1533 FSEND );
1535 exportGrouping( );
1536 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1537 exportAllSeries( xChartType, nAttachedAxis );
1538 exportAxesId( nAttachedAxis );
1540 pFS->endElement( FSNS( XML_c, nTypeId ) );
1543 void ChartExport::exportBarChart( Reference< chart2::XChartType > xChartType )
1545 sal_Int32 nTypeId = XML_barChart;
1546 if( mbIs3DChart )
1547 nTypeId = XML_bar3DChart;
1548 FSHelperPtr pFS = GetFS();
1549 pFS->startElement( FSNS( XML_c, nTypeId ),
1550 FSEND );
1551 // bar direction
1552 bool bVertical = false;
1553 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
1554 if( GetProperty( xPropSet, "Vertical" ) )
1555 mAny >>= bVertical;
1557 const char* bardir = bVertical? "bar":"col";
1558 pFS->singleElement( FSNS( XML_c, XML_barDir ),
1559 XML_val, bardir,
1560 FSEND );
1562 exportGrouping( true );
1564 const char* varyColors = "0";
1565 pFS->singleElement( FSNS( XML_c, XML_varyColors ),
1566 XML_val, varyColors,
1567 FSEND );
1569 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1570 exportAllSeries( xChartType, nAttachedAxis );
1572 Reference< XPropertySet > xTypeProp( xChartType, uno::UNO_QUERY );
1574 if( xTypeProp.is() && GetProperty( xTypeProp, "GapwidthSequence") )
1576 uno::Sequence< sal_Int32 > aBarPositionSequence;
1577 mAny >>= aBarPositionSequence;
1578 if( aBarPositionSequence.getLength() )
1580 sal_Int32 nGapWidth = aBarPositionSequence[0];
1581 pFS->singleElement( FSNS( XML_c, XML_gapWidth ),
1582 XML_val, I32S( nGapWidth ),
1583 FSEND );
1587 if( mbIs3DChart )
1589 // Shape
1590 namespace cssc = css::chart;
1591 sal_Int32 nGeom3d = cssc::ChartSolidType::RECTANGULAR_SOLID;
1592 if( xPropSet.is() && GetProperty( xPropSet, "SolidType") )
1593 mAny >>= nGeom3d;
1594 const char* sShapeType = NULL;
1595 switch( nGeom3d )
1597 case cssc::ChartSolidType::RECTANGULAR_SOLID:
1598 sShapeType = "box";
1599 break;
1600 case cssc::ChartSolidType::CONE:
1601 sShapeType = "cone";
1602 break;
1603 case cssc::ChartSolidType::CYLINDER:
1604 sShapeType = "cylinder";
1605 break;
1606 case cssc::ChartSolidType::PYRAMID:
1607 sShapeType = "pyramid";
1608 break;
1610 pFS->singleElement( FSNS( XML_c, XML_shape ),
1611 XML_val, sShapeType,
1612 FSEND );
1615 //overlap
1616 if( !mbIs3DChart && xTypeProp.is() && GetProperty( xTypeProp, "OverlapSequence") )
1618 uno::Sequence< sal_Int32 > aBarPositionSequence;
1619 mAny >>= aBarPositionSequence;
1620 if( aBarPositionSequence.getLength() )
1622 sal_Int32 nOverlap = aBarPositionSequence[0];
1623 pFS->singleElement( FSNS( XML_c, XML_overlap ),
1624 XML_val, I32S( nOverlap ),
1625 FSEND );
1629 exportAxesId( nAttachedAxis );
1631 pFS->endElement( FSNS( XML_c, nTypeId ) );
1634 void ChartExport::exportBubbleChart( Reference< chart2::XChartType > xChartType )
1636 FSHelperPtr pFS = GetFS();
1637 pFS->startElement( FSNS( XML_c, XML_bubbleChart ),
1638 FSEND );
1640 const char* varyColors = "0";
1641 pFS->singleElement( FSNS( XML_c, XML_varyColors ),
1642 XML_val, varyColors,
1643 FSEND );
1645 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1646 exportAllSeries( xChartType, nAttachedAxis );
1648 pFS->singleElement(FSNS(XML_c, XML_bubble3D),
1649 XML_val, "0",
1650 FSEND);
1652 exportAxesId( nAttachedAxis );
1654 pFS->endElement( FSNS( XML_c, XML_bubbleChart ) );
1657 void ChartExport::exportDoughnutChart( Reference< chart2::XChartType > xChartType )
1659 FSHelperPtr pFS = GetFS();
1660 pFS->startElement( FSNS( XML_c, XML_doughnutChart ),
1661 FSEND );
1663 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1664 exportAllSeries( xChartType, nAttachedAxis );
1665 // firstSliceAng
1666 exportFirstSliceAng( );
1667 //FIXME: holeSize
1668 sal_Int32 nHoleSize = 50;
1669 pFS->singleElement( FSNS( XML_c, XML_holeSize ),
1670 XML_val, I32S( nHoleSize ),
1671 FSEND );
1673 pFS->endElement( FSNS( XML_c, XML_doughnutChart ) );
1676 namespace {
1678 std::vector<Sequence<Reference<chart2::XDataSeries> > > splitDataSeriesByAxis(Reference< chart2::XChartType > xChartType)
1680 std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitSeries;
1681 std::map<sal_Int32, size_t> aMapAxisToIndex;
1683 Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
1684 if(xDSCnt.is())
1686 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
1687 for (sal_Int32 nIndex = 0, nEnd = aSeriesSeq.getLength(); nIndex < nEnd; ++nIndex)
1689 uno::Reference<chart2::XDataSeries> xSeries = aSeriesSeq[nIndex];
1690 Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
1691 if (!xPropSet.is())
1692 continue;
1694 sal_Int32 nAxisIndex = -1;
1695 uno::Any aAny = xPropSet->getPropertyValue("AttachedAxisIndex");
1696 aAny >>= nAxisIndex;
1697 size_t nVectorPos = 0;
1699 auto it = aMapAxisToIndex.find(nAxisIndex);
1700 if (it == aMapAxisToIndex.end())
1702 aSplitSeries.push_back(Sequence<Reference<chart2::XDataSeries> >());
1703 nVectorPos = aSplitSeries.size() - 1;
1704 aMapAxisToIndex.insert(std::pair<sal_Int32, size_t>(nAxisIndex, nVectorPos));
1707 uno::Sequence<Reference<chart2::XDataSeries> >& rAxisSeriesSeq = aSplitSeries[nVectorPos];
1708 sal_Int32 nLength = rAxisSeriesSeq.getLength();
1709 rAxisSeriesSeq.realloc(nLength + 1);
1710 rAxisSeriesSeq[nLength] = xSeries;
1714 return aSplitSeries;
1719 void ChartExport::exportLineChart( Reference< chart2::XChartType > xChartType )
1721 FSHelperPtr pFS = GetFS();
1722 std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
1723 for (auto itr = aSplitDataSeries.begin(), itrEnd = aSplitDataSeries.end();
1724 itr != itrEnd; ++itr)
1726 if (itr->getLength() == 0)
1727 continue;
1729 sal_Int32 nTypeId = XML_lineChart;
1730 if( mbIs3DChart )
1731 nTypeId = XML_line3DChart;
1732 pFS->startElement( FSNS( XML_c, nTypeId ),
1733 FSEND );
1735 exportGrouping( );
1736 // TODO: show marker symbol in series?
1737 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1738 exportSeries( xChartType, *itr, nAttachedAxis );
1740 // show marker?
1741 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
1742 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
1743 if( GetProperty( xPropSet, "SymbolType" ) )
1744 mAny >>= nSymbolType;
1746 if( !mbIs3DChart )
1748 exportHiLowLines();
1749 exportUpDownBars(xChartType);
1750 const char* marker = nSymbolType == css::chart::ChartSymbolType::NONE? "0":"1";
1751 pFS->singleElement( FSNS( XML_c, XML_marker ),
1752 XML_val, marker,
1753 FSEND );
1756 exportAxesId( nAttachedAxis );
1758 pFS->endElement( FSNS( XML_c, nTypeId ) );
1762 void ChartExport::exportPieChart( Reference< chart2::XChartType > xChartType )
1764 sal_Int32 eChartType = getChartType( );
1765 if(eChartType == chart::TYPEID_DOUGHNUT)
1767 exportDoughnutChart( xChartType );
1768 return;
1770 FSHelperPtr pFS = GetFS();
1771 sal_Int32 nTypeId = XML_pieChart;
1772 if( mbIs3DChart )
1773 nTypeId = XML_pie3DChart;
1774 pFS->startElement( FSNS( XML_c, nTypeId ),
1775 FSEND );
1776 // TODO: varyColors
1777 const char* varyColors = "1";
1778 pFS->singleElement( FSNS( XML_c, XML_varyColors ),
1779 XML_val, varyColors,
1780 FSEND );
1782 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1783 exportAllSeries( xChartType, nAttachedAxis );
1785 if( !mbIs3DChart )
1787 // firstSliceAng
1788 exportFirstSliceAng( );
1791 pFS->endElement( FSNS( XML_c, nTypeId ) );
1794 void ChartExport::exportRadarChart( Reference< chart2::XChartType > xChartType)
1796 FSHelperPtr pFS = GetFS();
1797 pFS->startElement( FSNS( XML_c, XML_radarChart ),
1798 FSEND );
1800 // radarStyle
1801 sal_Int32 eChartType = getChartType( );
1802 const char* radarStyle = NULL;
1803 if( eChartType == chart::TYPEID_RADARAREA )
1804 radarStyle = "filled";
1805 else
1806 radarStyle = "marker";
1807 pFS->singleElement( FSNS( XML_c, XML_radarStyle ),
1808 XML_val, radarStyle,
1809 FSEND );
1810 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1811 exportAllSeries( xChartType, nAttachedAxis );
1812 exportAxesId( nAttachedAxis );
1814 pFS->endElement( FSNS( XML_c, XML_radarChart ) );
1817 void ChartExport::exportScatterChart( Reference< chart2::XChartType > xChartType )
1819 FSHelperPtr pFS = GetFS();
1820 std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
1821 for (auto itr = aSplitDataSeries.begin(), itrEnd = aSplitDataSeries.end();
1822 itr != itrEnd; ++itr)
1824 if (itr->getLength() == 0)
1825 continue;
1827 pFS->startElement( FSNS( XML_c, XML_scatterChart ),
1828 FSEND );
1829 // TODO:scatterStyle
1831 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
1832 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
1833 if( GetProperty( xPropSet, "SymbolType" ) )
1834 mAny >>= nSymbolType;
1836 const char* scatterStyle = "lineMarker";
1837 if (nSymbolType == css::chart::ChartSymbolType::NONE)
1839 scatterStyle = "line";
1842 pFS->singleElement( FSNS( XML_c, XML_scatterStyle ),
1843 XML_val, scatterStyle,
1844 FSEND );
1846 pFS->singleElement( FSNS( XML_c, XML_varyColors ),
1847 XML_val, "0",
1848 FSEND );
1850 // FIXME: should export xVal and yVal
1851 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1852 exportSeries( xChartType, *itr, nAttachedAxis );
1853 exportAxesId( nAttachedAxis );
1855 pFS->endElement( FSNS( XML_c, XML_scatterChart ) );
1859 void ChartExport::exportStockChart( Reference< chart2::XChartType > xChartType )
1861 FSHelperPtr pFS = GetFS();
1862 pFS->startElement( FSNS( XML_c, XML_stockChart ),
1863 FSEND );
1865 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1867 bool bJapaneseCandleSticks = false;
1868 Reference< beans::XPropertySet > xCTProp( xChartType, uno::UNO_QUERY );
1869 if( xCTProp.is())
1870 xCTProp->getPropertyValue("Japanese") >>= bJapaneseCandleSticks;
1872 Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
1873 if(xDSCnt.is())
1874 exportCandleStickSeries(
1875 xDSCnt->getDataSeries(), bJapaneseCandleSticks, nAttachedAxis );
1877 // export stock properties
1878 Reference< css::chart::XStatisticDisplay > xStockPropProvider( mxDiagram, uno::UNO_QUERY );
1879 if( xStockPropProvider.is())
1881 exportHiLowLines();
1882 exportUpDownBars(xChartType);
1885 exportAxesId( nAttachedAxis );
1887 pFS->endElement( FSNS( XML_c, XML_stockChart ) );
1890 void ChartExport::exportHiLowLines()
1892 FSHelperPtr pFS = GetFS();
1893 // export the chart property
1894 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
1896 if (!xChartPropProvider.is())
1897 return;
1899 Reference< beans::XPropertySet > xStockPropSet = xChartPropProvider->getMinMaxLine();
1900 if( !xStockPropSet.is() )
1901 return;
1903 pFS->startElement( FSNS( XML_c, XML_hiLowLines ),
1904 FSEND );
1905 exportShapeProps( xStockPropSet );
1906 pFS->endElement( FSNS( XML_c, XML_hiLowLines ) );
1909 void ChartExport::exportUpDownBars( Reference< chart2::XChartType > xChartType)
1911 if(xChartType->getChartType() != "com.sun.star.chart2.CandleStickChartType")
1912 return;
1914 FSHelperPtr pFS = GetFS();
1915 // export the chart property
1916 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
1917 if(xChartPropProvider.is())
1919 // updownbar
1920 pFS->startElement( FSNS( XML_c, XML_upDownBars ),
1921 FSEND );
1922 // TODO: gapWidth
1923 sal_Int32 nGapWidth = 150;
1924 pFS->singleElement( FSNS( XML_c, XML_gapWidth ),
1925 XML_val, I32S( nGapWidth ),
1926 FSEND );
1928 Reference< beans::XPropertySet > xChartPropSet = xChartPropProvider->getUpBar();
1929 if( xChartPropSet.is() )
1931 pFS->startElement( FSNS( XML_c, XML_upBars ),
1932 FSEND );
1933 // For Linechart with UpDownBars, spPr is not getting imported
1934 // so no need to call the exportShapeProps() for LineChart
1935 if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
1937 exportShapeProps(xChartPropSet);
1939 pFS->endElement( FSNS( XML_c, XML_upBars ) );
1941 xChartPropSet = xChartPropProvider->getDownBar();
1942 if( xChartPropSet.is() )
1944 pFS->startElement( FSNS( XML_c, XML_downBars ),
1945 FSEND );
1946 if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
1948 exportShapeProps(xChartPropSet);
1950 pFS->endElement( FSNS( XML_c, XML_downBars ) );
1952 pFS->endElement( FSNS( XML_c, XML_upDownBars ) );
1956 void ChartExport::exportSurfaceChart( Reference< chart2::XChartType > xChartType )
1958 FSHelperPtr pFS = GetFS();
1959 sal_Int32 nTypeId = XML_surfaceChart;
1960 if( mbIs3DChart )
1961 nTypeId = XML_surface3DChart;
1962 pFS->startElement( FSNS( XML_c, nTypeId ),
1963 FSEND );
1964 sal_Int32 nAttachedAxis = AXIS_PRIMARY_Y;
1965 exportAllSeries( xChartType, nAttachedAxis );
1966 exportAxesId( nAttachedAxis );
1968 pFS->endElement( FSNS( XML_c, nTypeId ) );
1971 void ChartExport::exportAllSeries(Reference<chart2::XChartType> xChartType, sal_Int32& rAttachedAxis)
1973 Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
1974 if( ! xDSCnt.is())
1975 return;
1977 // export dataseries for current chart-type
1978 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
1979 exportSeries(xChartType, aSeriesSeq, rAttachedAxis);
1982 void ChartExport::exportSeries( Reference<chart2::XChartType> xChartType,
1983 Sequence<Reference<chart2::XDataSeries> >& rSeriesSeq, sal_Int32& rAttachedAxis )
1985 OUString aLabelRole = xChartType->getRoleOfSequenceForSeriesLabel();
1986 OUString aChartType( xChartType->getChartType());
1987 sal_Int32 eChartType = lcl_getChartType( aChartType );
1989 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<rSeriesSeq.getLength(); ++nSeriesIdx )
1991 // export series
1992 Reference< chart2::data::XDataSource > xSource( rSeriesSeq[nSeriesIdx], uno::UNO_QUERY );
1993 if( xSource.is())
1995 Reference< chart2::XDataSeries > xDataSeries( xSource, uno::UNO_QUERY );
1996 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
1997 xSource->getDataSequences());
1998 // search for main sequence and create a series element
2000 sal_Int32 nMainSequenceIndex = -1;
2001 sal_Int32 nSeriesLength = 0;
2002 Reference< chart2::data::XDataSequence > xValuesSeq;
2003 Reference< chart2::data::XDataSequence > xLabelSeq;
2004 sal_Int32 nSeqIdx=0;
2005 for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2007 OUString aRole;
2008 Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2009 if( nMainSequenceIndex==-1 )
2011 Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2012 if( xSeqProp.is())
2013 xSeqProp->getPropertyValue("Role") >>= aRole;
2014 // "main" sequence
2015 if( aRole.equals( aLabelRole ))
2017 xValuesSeq.set( xTempValueSeq );
2018 xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2019 nMainSequenceIndex = nSeqIdx;
2022 sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2023 if( nSeriesLength < nSequenceLength )
2024 nSeriesLength = nSequenceLength;
2027 // have found the main sequence, then xValuesSeq and
2028 // xLabelSeq contain those. Otherwise both are empty
2030 FSHelperPtr pFS = GetFS();
2031 pFS->startElement( FSNS( XML_c, XML_ser ),
2032 FSEND );
2034 // TODO: idx and order
2035 pFS->singleElement( FSNS( XML_c, XML_idx ),
2036 XML_val, I32S(mnSeriesCount),
2037 FSEND );
2038 pFS->singleElement( FSNS( XML_c, XML_order ),
2039 XML_val, I32S(mnSeriesCount++),
2040 FSEND );
2042 // export label
2043 if( xLabelSeq.is() )
2044 exportSeriesText( xLabelSeq );
2046 Reference<XPropertySet> xPropSet(xDataSeries, UNO_QUERY_THROW);
2047 if( GetProperty( xPropSet, "AttachedAxisIndex") )
2049 sal_Int32 nLocalAttachedAxis;
2050 mAny >>= nLocalAttachedAxis;
2051 rAttachedAxis = translateFromChart2AxisIndexToOox(nLocalAttachedAxis);
2054 // export shape properties
2055 Reference< XPropertySet > xOldPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet(
2056 rSeriesSeq[nSeriesIdx], getModel() );
2057 if( xOldPropSet.is() )
2059 exportShapeProps( xOldPropSet );
2062 switch( eChartType )
2064 case chart::TYPEID_BUBBLE:
2065 case chart::TYPEID_HORBAR:
2066 case chart::TYPEID_BAR:
2068 pFS->singleElement(FSNS(XML_c, XML_invertIfNegative),
2069 XML_val, "0",
2070 FSEND);
2072 break;
2073 case chart::TYPEID_LINE:
2075 exportMarker(xDataSeries);
2076 break;
2078 case chart::TYPEID_PIE:
2079 case chart::TYPEID_DOUGHNUT:
2081 if( xOldPropSet.is() && GetProperty( xOldPropSet, "SegmentOffset") )
2083 sal_Int32 nOffset = 0;
2084 mAny >>= nOffset;
2085 pFS->singleElement( FSNS( XML_c, XML_explosion ),
2086 XML_val, I32S( nOffset ),
2087 FSEND );
2089 break;
2091 case chart::TYPEID_SCATTER:
2093 exportMarker(xDataSeries);
2094 break;
2096 case chart::TYPEID_RADARLINE:
2098 exportMarker(xDataSeries);
2099 break;
2103 // export data points
2104 exportDataPoints( uno::Reference< beans::XPropertySet >( rSeriesSeq[nSeriesIdx], uno::UNO_QUERY ), nSeriesLength );
2106 // export data labels
2107 exportDataLabels(rSeriesSeq[nSeriesIdx], nSeriesLength, eChartType);
2109 exportTrendlines( rSeriesSeq[nSeriesIdx] );
2111 if( eChartType != chart::TYPEID_PIE &&
2112 eChartType != chart::TYPEID_RADARLINE )
2114 //export error bars here
2115 Reference< XPropertySet > xSeriesPropSet( xSource, uno::UNO_QUERY );
2116 Reference< XPropertySet > xErrorBarYProps;
2117 xSeriesPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarYProps;
2118 if(xErrorBarYProps.is())
2119 exportErrorBar(xErrorBarYProps, true);
2120 if (eChartType != chart::TYPEID_BAR &&
2121 eChartType != chart::TYPEID_HORBAR)
2123 Reference< XPropertySet > xErrorBarXProps;
2124 xSeriesPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarXProps;
2125 if(xErrorBarXProps.is())
2126 exportErrorBar(xErrorBarXProps, false);
2130 // export categories
2131 if( eChartType != chart::TYPEID_SCATTER && mxCategoriesValues.is() )
2132 exportSeriesCategory( mxCategoriesValues );
2134 if( (eChartType == chart::TYPEID_SCATTER)
2135 || (eChartType == chart::TYPEID_BUBBLE) )
2137 // export xVal
2138 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, OUString("values-x") ) );
2139 if( xSequence.is() )
2141 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2142 if( xValues.is() )
2143 exportSeriesValues( xValues, XML_xVal );
2147 if( eChartType == chart::TYPEID_BUBBLE )
2149 // export yVal
2150 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, OUString("values-y") ) );
2151 if( xSequence.is() )
2153 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2154 if( xValues.is() )
2155 exportSeriesValues( xValues, XML_yVal );
2159 // export values
2160 if( xValuesSeq.is() )
2162 sal_Int32 nYValueType = XML_val;
2163 if( eChartType == chart::TYPEID_SCATTER )
2164 nYValueType = XML_yVal;
2165 else if( eChartType == chart::TYPEID_BUBBLE )
2166 nYValueType = XML_bubbleSize;
2167 exportSeriesValues( xValuesSeq, nYValueType );
2170 if( eChartType == chart::TYPEID_SCATTER
2171 || eChartType == chart::TYPEID_LINE )
2172 exportSmooth();
2174 pFS->endElement( FSNS( XML_c, XML_ser ) );
2181 void ChartExport::exportCandleStickSeries(
2182 const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
2183 bool /*bJapaneseCandleSticks*/,
2184 sal_Int32& rAttachedAxis )
2186 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx )
2188 Reference< chart2::XDataSeries > xSeries( aSeriesSeq[nSeriesIdx] );
2189 rAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries ) ? AXIS_PRIMARY_Y : AXIS_SECONDARY_Y;
2191 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
2192 if( xSource.is())
2194 // export series in correct order (as we don't store roles)
2195 // with japanese candlesticks: open, low, high, close
2196 // otherwise: low, high, close
2197 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
2198 xSource->getDataSequences());
2200 Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
2201 const char* sSeries[] = {"values-first","values-max","values-min","values-last",0};
2203 for( sal_Int32 idx = 0; sSeries[idx] != 0 ; idx++ )
2205 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii(sSeries[idx]) ) );
2206 if( xLabeledSeq.is())
2208 Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
2209 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
2211 FSHelperPtr pFS = GetFS();
2212 pFS->startElement( FSNS( XML_c, XML_ser ),
2213 FSEND );
2215 // TODO: idx and order
2216 // idx attribute should start from 1 and not from 0.
2217 pFS->singleElement( FSNS( XML_c, XML_idx ),
2218 XML_val, I32S(idx+1),
2219 FSEND );
2220 pFS->singleElement( FSNS( XML_c, XML_order ),
2221 XML_val, I32S(idx+1),
2222 FSEND );
2224 // export label
2225 if( xLabelSeq.is() )
2226 exportSeriesText( xLabelSeq );
2228 // TODO:export shape properties
2230 // export categories
2231 if( mxCategoriesValues.is() )
2232 exportSeriesCategory( mxCategoriesValues );
2234 // export values
2235 if( xValueSeq.is() )
2236 exportSeriesValues( xValueSeq );
2238 pFS->endElement( FSNS( XML_c, XML_ser ) );
2246 void ChartExport::exportSeriesText( const Reference< chart2::data::XDataSequence > & xValueSeq )
2248 FSHelperPtr pFS = GetFS();
2249 Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
2250 pFS->startElement( FSNS( XML_c, XML_tx ),
2251 FSEND );
2253 OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
2254 aCellRange = parseFormula( aCellRange );
2255 pFS->startElement( FSNS( XML_c, XML_strRef ),
2256 FSEND );
2258 pFS->startElement( FSNS( XML_c, XML_f ),
2259 FSEND );
2260 pFS->writeEscaped( aCellRange );
2261 pFS->endElement( FSNS( XML_c, XML_f ) );
2263 OUString aLabelString = lcl_getLabelString( xValueSeq );
2264 pFS->startElement( FSNS( XML_c, XML_strCache ),
2265 FSEND );
2266 pFS->singleElement( FSNS( XML_c, XML_ptCount ),
2267 XML_val, "1",
2268 FSEND );
2269 pFS->startElement( FSNS( XML_c, XML_pt ),
2270 XML_idx, "0",
2271 FSEND );
2272 pFS->startElement( FSNS( XML_c, XML_v ),
2273 FSEND );
2274 pFS->writeEscaped( aLabelString );
2275 pFS->endElement( FSNS( XML_c, XML_v ) );
2276 pFS->endElement( FSNS( XML_c, XML_pt ) );
2277 pFS->endElement( FSNS( XML_c, XML_strCache ) );
2278 pFS->endElement( FSNS( XML_c, XML_strRef ) );
2279 pFS->endElement( FSNS( XML_c, XML_tx ) );
2282 void ChartExport::exportSeriesCategory( const Reference< chart2::data::XDataSequence > & xValueSeq )
2284 FSHelperPtr pFS = GetFS();
2285 Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
2286 pFS->startElement( FSNS( XML_c, XML_cat ),
2287 FSEND );
2289 OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2290 aCellRange = parseFormula( aCellRange );
2291 // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2292 pFS->startElement( FSNS( XML_c, XML_strRef ),
2293 FSEND );
2295 pFS->startElement( FSNS( XML_c, XML_f ),
2296 FSEND );
2297 pFS->writeEscaped( aCellRange );
2298 pFS->endElement( FSNS( XML_c, XML_f ) );
2300 ::std::vector< OUString > aCategories;
2301 lcl_fillCategoriesIntoStringVector( xValueSeq, aCategories );
2302 sal_Int32 ptCount = aCategories.size();
2303 pFS->startElement( FSNS( XML_c, XML_strCache ),
2304 FSEND );
2305 pFS->singleElement( FSNS( XML_c, XML_ptCount ),
2306 XML_val, I32S( ptCount ),
2307 FSEND );
2308 for( sal_Int32 i = 0; i < ptCount; i++ )
2310 pFS->startElement( FSNS( XML_c, XML_pt ),
2311 XML_idx, I32S( i ),
2312 FSEND );
2313 pFS->startElement( FSNS( XML_c, XML_v ),
2314 FSEND );
2315 pFS->writeEscaped( aCategories[i] );
2316 pFS->endElement( FSNS( XML_c, XML_v ) );
2317 pFS->endElement( FSNS( XML_c, XML_pt ) );
2320 pFS->endElement( FSNS( XML_c, XML_strCache ) );
2321 pFS->endElement( FSNS( XML_c, XML_strRef ) );
2322 pFS->endElement( FSNS( XML_c, XML_cat ) );
2325 void ChartExport::exportSeriesValues( const Reference< chart2::data::XDataSequence > & xValueSeq, sal_Int32 nValueType )
2327 FSHelperPtr pFS = GetFS();
2328 Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
2329 pFS->startElement( FSNS( XML_c, nValueType ),
2330 FSEND );
2332 OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2333 aCellRange = parseFormula( aCellRange );
2334 // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2335 pFS->startElement( FSNS( XML_c, XML_numRef ),
2336 FSEND );
2338 pFS->startElement( FSNS( XML_c, XML_f ),
2339 FSEND );
2340 pFS->writeEscaped( aCellRange );
2341 pFS->endElement( FSNS( XML_c, XML_f ) );
2343 ::std::vector< double > aValues;
2344 aValues = lcl_getAllValuesFromSequence( xValueSeq );
2345 sal_Int32 ptCount = aValues.size();
2346 pFS->startElement( FSNS( XML_c, XML_numCache ),
2347 FSEND );
2348 pFS->startElement( FSNS( XML_c, XML_formatCode ),
2349 FSEND );
2350 // TODO: what format code?
2351 pFS->writeEscaped( "General" );
2352 pFS->endElement( FSNS( XML_c, XML_formatCode ) );
2353 pFS->singleElement( FSNS( XML_c, XML_ptCount ),
2354 XML_val, I32S( ptCount ),
2355 FSEND );
2357 bool bIsNumberValue = true;
2358 bool bXSeriesValue = false;
2359 double Value = 1.0;
2361 if(nValueType == XML_xVal)
2362 bXSeriesValue = true;
2364 for( sal_Int32 i = 0; i < ptCount; i++ )
2366 pFS->startElement( FSNS( XML_c, XML_pt ),
2367 XML_idx, I32S( i ),
2368 FSEND );
2369 pFS->startElement( FSNS( XML_c, XML_v ),
2370 FSEND );
2371 if (bIsNumberValue && !rtl::math::isNan(aValues[i]))
2372 pFS->write( aValues[i] );
2373 else if(bXSeriesValue)
2375 //In Case aValues is not a number for X Values...We write X values as 1,2,3....MS Word does the same thing.
2376 pFS->write( Value );
2377 Value = Value + 1;
2378 bIsNumberValue = false;
2380 pFS->endElement( FSNS( XML_c, XML_v ) );
2381 pFS->endElement( FSNS( XML_c, XML_pt ) );
2384 pFS->endElement( FSNS( XML_c, XML_numCache ) );
2385 pFS->endElement( FSNS( XML_c, XML_numRef ) );
2386 pFS->endElement( FSNS( XML_c, nValueType ) );
2389 void ChartExport::exportShapeProps( Reference< XPropertySet > xPropSet )
2391 FSHelperPtr pFS = GetFS();
2392 pFS->startElement( FSNS( XML_c, XML_spPr ),
2393 FSEND );
2395 WriteFill( xPropSet );
2396 WriteOutline( xPropSet );
2398 pFS->endElement( FSNS( XML_c, XML_spPr ) );
2401 void ChartExport::exportTextProps(Reference<XPropertySet> xPropSet)
2403 FSHelperPtr pFS = GetFS();
2404 pFS->startElement(FSNS(XML_c, XML_txPr), FSEND);
2406 pFS->startElement(FSNS(XML_a, XML_bodyPr), FSEND);
2407 pFS->endElement(FSNS(XML_a, XML_bodyPr));
2409 pFS->startElement(FSNS(XML_a, XML_p), FSEND);
2410 pFS->startElement(FSNS(XML_a, XML_pPr), FSEND);
2412 WriteRunProperties(xPropSet, false, XML_defRPr);
2414 pFS->endElement(FSNS(XML_a, XML_pPr));
2415 pFS->endElement(FSNS(XML_a, XML_p));
2417 pFS->endElement(FSNS(XML_c, XML_txPr));
2420 void ChartExport::InitPlotArea( )
2422 Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
2424 // Check for supported services and then the properties provided by this service.
2425 Reference<lang::XServiceInfo> xServiceInfo (mxDiagram, uno::UNO_QUERY);
2426 if (xServiceInfo.is())
2428 if (xServiceInfo->supportsService(
2429 OUString("com.sun.star.chart.ChartAxisZSupplier")))
2431 xDiagramProperties->getPropertyValue(
2432 OUString("HasZAxis")) >>= mbHasZAxis;
2436 xDiagramProperties->getPropertyValue(
2437 OUString ("Dim3D")) >>= mbIs3DChart;
2439 Reference< chart2::XChartDocument > xNewDoc( getModel(), uno::UNO_QUERY );
2440 if( mbHasCategoryLabels && mxNewDiagram.is())
2442 Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( mxNewDiagram ) );
2443 if( xCategories.is() )
2445 mxCategoriesValues.set( xCategories->getValues() );
2450 void ChartExport::exportAxes( )
2452 sal_Int32 nSize = maAxes.size();
2453 for( sal_Int32 nIdx = 0; nIdx < nSize; nIdx++ )
2455 exportAxis( maAxes[nIdx] );
2459 void ChartExport::exportAxis(const AxisIdPair& rAxisIdPair)
2461 // get some properties from document first
2462 bool bHasXAxisTitle = false,
2463 bHasYAxisTitle = false,
2464 bHasZAxisTitle = false,
2465 bHasSecondaryXAxisTitle = false,
2466 bHasSecondaryYAxisTitle = false;
2467 bool bHasXAxisMajorGrid = false,
2468 bHasXAxisMinorGrid = false,
2469 bHasYAxisMajorGrid = false,
2470 bHasYAxisMinorGrid = false,
2471 bHasZAxisMajorGrid = false,
2472 bHasZAxisMinorGrid = false;
2474 Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
2476 xDiagramProperties->getPropertyValue(
2477 OUString ("HasXAxisTitle")) >>= bHasXAxisTitle;
2478 xDiagramProperties->getPropertyValue(
2479 OUString ("HasYAxisTitle")) >>= bHasYAxisTitle;
2480 xDiagramProperties->getPropertyValue(
2481 OUString ("HasZAxisTitle")) >>= bHasZAxisTitle;
2482 xDiagramProperties->getPropertyValue(
2483 OUString ("HasSecondaryXAxisTitle")) >>= bHasSecondaryXAxisTitle;
2484 xDiagramProperties->getPropertyValue(
2485 OUString ("HasSecondaryYAxisTitle")) >>= bHasSecondaryYAxisTitle;
2487 xDiagramProperties->getPropertyValue(
2488 OUString ("HasXAxisGrid")) >>= bHasXAxisMajorGrid;
2489 xDiagramProperties->getPropertyValue(
2490 OUString ("HasYAxisGrid")) >>= bHasYAxisMajorGrid;
2491 xDiagramProperties->getPropertyValue(
2492 OUString ("HasZAxisGrid")) >>= bHasZAxisMajorGrid;
2494 xDiagramProperties->getPropertyValue(
2495 OUString ("HasXAxisHelpGrid")) >>= bHasXAxisMinorGrid;
2496 xDiagramProperties->getPropertyValue(
2497 OUString ("HasYAxisHelpGrid")) >>= bHasYAxisMinorGrid;
2498 xDiagramProperties->getPropertyValue(
2499 OUString ("HasZAxisHelpGrid")) >>= bHasZAxisMinorGrid;
2501 Reference< XPropertySet > xAxisProp;
2502 Reference< drawing::XShape > xAxisTitle;
2503 Reference< beans::XPropertySet > xMajorGrid;
2504 Reference< beans::XPropertySet > xMinorGrid;
2505 sal_Int32 nAxisType = XML_catAx;
2506 const char* sAxPos = NULL;
2508 switch( rAxisIdPair.nAxisType )
2510 case AXIS_PRIMARY_X:
2512 Reference< css::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
2513 if( xAxisXSupp.is())
2514 xAxisProp = xAxisXSupp->getXAxis();
2515 if( bHasXAxisTitle )
2516 xAxisTitle.set( xAxisXSupp->getXAxisTitle(), uno::UNO_QUERY );
2517 if( bHasXAxisMajorGrid )
2518 xMajorGrid.set( xAxisXSupp->getXMainGrid(), uno::UNO_QUERY );
2519 if( bHasXAxisMinorGrid )
2520 xMinorGrid.set( xAxisXSupp->getXHelpGrid(), uno::UNO_QUERY );
2522 sal_Int32 eChartType = getChartType( );
2523 if( (eChartType == chart::TYPEID_SCATTER)
2524 || (eChartType == chart::TYPEID_BUBBLE) )
2525 nAxisType = XML_valAx;
2526 else if( eChartType == chart::TYPEID_STOCK )
2527 nAxisType = XML_dateAx;
2528 // FIXME: axPos, need to check axis direction
2529 sAxPos = "b";
2530 break;
2532 case AXIS_PRIMARY_Y:
2534 Reference< css::chart::XAxisYSupplier > xAxisYSupp( mxDiagram, uno::UNO_QUERY );
2535 if( xAxisYSupp.is())
2536 xAxisProp = xAxisYSupp->getYAxis();
2537 if( bHasYAxisTitle )
2538 xAxisTitle.set( xAxisYSupp->getYAxisTitle(), uno::UNO_QUERY );
2539 if( bHasYAxisMajorGrid )
2540 xMajorGrid.set( xAxisYSupp->getYMainGrid(), uno::UNO_QUERY );
2541 if( bHasYAxisMinorGrid )
2542 xMinorGrid.set( xAxisYSupp->getYHelpGrid(), uno::UNO_QUERY );
2544 nAxisType = XML_valAx;
2545 // FIXME: axPos, need to check axis direction
2546 sAxPos = "l";
2547 break;
2549 case AXIS_PRIMARY_Z:
2551 Reference< css::chart::XAxisZSupplier > xAxisZSupp( mxDiagram, uno::UNO_QUERY );
2552 if( xAxisZSupp.is())
2553 xAxisProp = xAxisZSupp->getZAxis();
2554 if( bHasZAxisTitle )
2555 xAxisTitle.set( xAxisZSupp->getZAxisTitle(), uno::UNO_QUERY );
2556 if( bHasZAxisMajorGrid )
2557 xMajorGrid.set( xAxisZSupp->getZMainGrid(), uno::UNO_QUERY );
2558 if( bHasZAxisMinorGrid )
2559 xMinorGrid.set( xAxisZSupp->getZHelpGrid(), uno::UNO_QUERY );
2561 sal_Int32 eChartType = getChartType( );
2562 if( (eChartType == chart::TYPEID_SCATTER)
2563 || (eChartType == chart::TYPEID_BUBBLE) )
2564 nAxisType = XML_valAx;
2565 else if( eChartType == chart::TYPEID_STOCK )
2566 nAxisType = XML_dateAx;
2567 // FIXME: axPos, need to check axis direction
2568 sAxPos = "b";
2569 break;
2571 case AXIS_SECONDARY_Y:
2573 Reference< css::chart::XTwoAxisYSupplier > xAxisTwoYSupp( mxDiagram, uno::UNO_QUERY );
2574 if( xAxisTwoYSupp.is())
2575 xAxisProp = xAxisTwoYSupp->getSecondaryYAxis();
2576 if( bHasSecondaryYAxisTitle )
2578 Reference< css::chart::XSecondAxisTitleSupplier > xAxisSupp( mxDiagram, uno::UNO_QUERY );
2579 xAxisTitle.set( xAxisSupp->getSecondYAxisTitle(), uno::UNO_QUERY );
2582 nAxisType = XML_valAx;
2583 // FIXME: axPos, need to check axis direction
2584 sAxPos = "r";
2585 break;
2589 _exportAxis(xAxisProp, xAxisTitle, xMajorGrid, xMinorGrid, nAxisType, sAxPos, rAxisIdPair);
2592 void ChartExport::_exportAxis(
2593 const Reference< XPropertySet >& xAxisProp,
2594 const Reference< drawing::XShape >& xAxisTitle,
2595 const Reference< XPropertySet >& xMajorGrid,
2596 const Reference< XPropertySet >& xMinorGrid,
2597 sal_Int32 nAxisType,
2598 const char* sAxisPos,
2599 const AxisIdPair& rAxisIdPair )
2601 FSHelperPtr pFS = GetFS();
2602 pFS->startElement( FSNS( XML_c, nAxisType ),
2603 FSEND );
2604 pFS->singleElement( FSNS( XML_c, XML_axId ),
2605 XML_val, I32S( rAxisIdPair.nAxisId ),
2606 FSEND );
2608 pFS->startElement( FSNS( XML_c, XML_scaling ),
2609 FSEND );
2611 // logBase, min, max
2612 if(GetProperty( xAxisProp, "Logarithmic" ) )
2614 bool bLogarithmic = false;
2615 mAny >>= bLogarithmic;
2616 if( bLogarithmic )
2618 // default value is 10?
2619 sal_Int32 nLogBase = 10;
2620 pFS->singleElement( FSNS( XML_c, XML_logBase ),
2621 XML_val, I32S( nLogBase ),
2622 FSEND );
2626 // orientation: minMax, maxMin
2627 bool bReverseDirection = false;
2628 if(GetProperty( xAxisProp, "ReverseDirection" ) )
2629 mAny >>= bReverseDirection;
2631 const char* orientation = bReverseDirection ? "maxMin":"minMax";
2632 pFS->singleElement( FSNS( XML_c, XML_orientation ),
2633 XML_val, orientation,
2634 FSEND );
2636 bool bAutoMax = false;
2637 if(GetProperty( xAxisProp, "AutoMax" ) )
2638 mAny >>= bAutoMax;
2640 if( !bAutoMax && (GetProperty( xAxisProp, "Max" ) ) )
2642 double dMax = 0;
2643 mAny >>= dMax;
2644 pFS->singleElement( FSNS( XML_c, XML_max ),
2645 XML_val, IS( dMax ),
2646 FSEND );
2649 bool bAutoMin = false;
2650 if(GetProperty( xAxisProp, "AutoMin" ) )
2651 mAny >>= bAutoMin;
2653 if( !bAutoMin && (GetProperty( xAxisProp, "Min" ) ) )
2655 double dMin = 0;
2656 mAny >>= dMin;
2657 pFS->singleElement( FSNS( XML_c, XML_min ),
2658 XML_val, IS( dMin ),
2659 FSEND );
2662 pFS->endElement( FSNS( XML_c, XML_scaling ) );
2664 bool bVisible = true;
2665 if( xAxisProp.is() )
2667 xAxisProp->getPropertyValue(
2668 OUString ("Visible")) >>= bVisible;
2671 // only export each axis only once non-deleted
2672 bool bDeleted = std::find(maExportedAxis.begin(),
2673 maExportedAxis.end(), rAxisIdPair.nAxisType) != maExportedAxis.end();
2675 if (!bDeleted)
2676 maExportedAxis.insert(rAxisIdPair.nAxisType);
2678 pFS->singleElement( FSNS( XML_c, XML_delete ),
2679 XML_val, !bDeleted && bVisible ? "0" : "1",
2680 FSEND );
2682 // FIXME: axPos, need to check the property "ReverseDirection"
2683 pFS->singleElement( FSNS( XML_c, XML_axPos ),
2684 XML_val, sAxisPos,
2685 FSEND );
2686 // major grid line
2687 if( xMajorGrid.is())
2689 pFS->startElement( FSNS( XML_c, XML_majorGridlines ),
2690 FSEND );
2691 exportShapeProps( xMajorGrid );
2692 pFS->endElement( FSNS( XML_c, XML_majorGridlines ) );
2695 // minor grid line
2696 if( xMinorGrid.is())
2698 pFS->startElement( FSNS( XML_c, XML_minorGridlines ),
2699 FSEND );
2700 exportShapeProps( xMinorGrid );
2701 pFS->endElement( FSNS( XML_c, XML_minorGridlines ) );
2704 // title
2705 if( xAxisTitle.is() )
2706 exportTitle( xAxisTitle );
2708 bool bLinkedNumFmt = true;
2709 if (GetProperty(xAxisProp, "LinkNumberFormatToSource"))
2710 mAny >>= bLinkedNumFmt;
2712 OUString aNumberFormatString("General");
2713 if (GetProperty(xAxisProp, "NumberFormat"))
2715 sal_Int32 nKey = 0;
2716 mAny >>= nKey;
2717 aNumberFormatString = getNumberFormatCode(nKey);
2720 OString sNumberFormatString = OUStringToOString(aNumberFormatString, RTL_TEXTENCODING_UTF8);
2721 pFS->singleElement(FSNS(XML_c, XML_numFmt),
2722 XML_formatCode, sNumberFormatString.getStr(),
2723 XML_sourceLinked, bLinkedNumFmt ? "1" : "0",
2724 FSEND);
2726 // majorTickMark
2727 sal_Int32 nValue = 0;
2728 if(GetProperty( xAxisProp, "Marks" ) )
2730 mAny >>= nValue;
2731 bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
2732 bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
2733 const char* majorTickMark = NULL;
2734 if( bInner && bOuter )
2735 majorTickMark = "cross";
2736 else if( bInner )
2737 majorTickMark = "in";
2738 else if( bOuter )
2739 majorTickMark = "out";
2740 else
2741 majorTickMark = "none";
2742 pFS->singleElement( FSNS( XML_c, XML_majorTickMark ),
2743 XML_val, majorTickMark,
2744 FSEND );
2746 // minorTickMark
2747 if(GetProperty( xAxisProp, "HelpMarks" ) )
2749 mAny >>= nValue;
2750 bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
2751 bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
2752 const char* minorTickMark = NULL;
2753 if( bInner && bOuter )
2754 minorTickMark = "cross";
2755 else if( bInner )
2756 minorTickMark = "in";
2757 else if( bOuter )
2758 minorTickMark = "out";
2759 else
2760 minorTickMark = "none";
2761 pFS->singleElement( FSNS( XML_c, XML_minorTickMark ),
2762 XML_val, minorTickMark,
2763 FSEND );
2765 // tickLblPos
2766 const char* sTickLblPos = NULL;
2767 bool bDisplayLabel = true;
2768 if(GetProperty( xAxisProp, "DisplayLabels" ) )
2769 mAny >>= bDisplayLabel;
2770 if( bDisplayLabel && (GetProperty( xAxisProp, "LabelPosition" ) ) )
2772 css::chart::ChartAxisLabelPosition eLabelPosition = css::chart::ChartAxisLabelPosition_NEAR_AXIS;
2773 mAny >>= eLabelPosition;
2774 switch( eLabelPosition )
2776 case css::chart::ChartAxisLabelPosition_NEAR_AXIS:
2777 case css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE:
2778 sTickLblPos = "nextTo";
2779 break;
2780 case css::chart::ChartAxisLabelPosition_OUTSIDE_START:
2781 sTickLblPos = "low";
2782 break;
2783 case css::chart::ChartAxisLabelPosition_OUTSIDE_END:
2784 sTickLblPos = "high";
2785 break;
2786 default:
2787 sTickLblPos = "nextTo";
2788 break;
2791 else
2793 sTickLblPos = "none";
2795 pFS->singleElement( FSNS( XML_c, XML_tickLblPos ),
2796 XML_val, sTickLblPos,
2797 FSEND );
2799 // shape properties
2800 exportShapeProps( xAxisProp );
2802 exportTextProps(xAxisProp);
2804 pFS->singleElement( FSNS( XML_c, XML_crossAx ),
2805 XML_val, I32S( rAxisIdPair.nCrossAx ),
2806 FSEND );
2808 // crosses & crossesAt
2809 bool bCrossesValue = false;
2810 const char* sCrosses = NULL;
2811 if(GetProperty( xAxisProp, "CrossoverPosition" ) )
2813 css::chart::ChartAxisPosition ePosition( css::chart::ChartAxisPosition_ZERO );
2814 mAny >>= ePosition;
2815 switch( ePosition )
2817 case css::chart::ChartAxisPosition_START:
2818 sCrosses = "min";
2819 break;
2820 case css::chart::ChartAxisPosition_END:
2821 sCrosses = "max";
2822 break;
2823 case css::chart::ChartAxisPosition_ZERO:
2824 sCrosses = "autoZero";
2825 break;
2826 default:
2827 bCrossesValue = true;
2828 break;
2832 if( bCrossesValue && GetProperty( xAxisProp, "CrossoverValue" ) )
2834 double dValue = 0;
2835 mAny >>= dValue;
2836 pFS->singleElement( FSNS( XML_c, XML_crossesAt ),
2837 XML_val, IS( dValue ),
2838 FSEND );
2840 else
2842 pFS->singleElement( FSNS( XML_c, XML_crosses ),
2843 XML_val, sCrosses,
2844 FSEND );
2847 if( ( nAxisType == XML_catAx )
2848 || ( nAxisType == XML_dateAx ) )
2850 // FIXME: seems not support? use default value,
2851 const char* isAuto = "1";
2852 pFS->singleElement( FSNS( XML_c, XML_auto ),
2853 XML_val, isAuto,
2854 FSEND );
2856 if( nAxisType == XML_catAx )
2858 // FIXME: seems not support? lblAlgn
2859 const char* sLblAlgn = "ctr";
2860 pFS->singleElement( FSNS( XML_c, XML_lblAlgn ),
2861 XML_val, sLblAlgn,
2862 FSEND );
2865 // FIXME: seems not support? lblOffset
2866 sal_Int32 nLblOffset = 100;
2867 pFS->singleElement( FSNS( XML_c, XML_lblOffset ),
2868 XML_val, I32S( nLblOffset ),
2869 FSEND );
2872 // majorUnit
2873 bool bAutoStepMain = false;
2874 if(GetProperty( xAxisProp, "AutoStepMain" ) )
2875 mAny >>= bAutoStepMain;
2877 if( !bAutoStepMain && (GetProperty( xAxisProp, "StepMain" ) ) )
2879 double dMajorUnit = 0;
2880 mAny >>= dMajorUnit;
2881 pFS->singleElement( FSNS( XML_c, XML_majorUnit ),
2882 XML_val, IS( dMajorUnit ),
2883 FSEND );
2885 // minorUnit
2886 bool bAutoStepHelp = false;
2887 if(GetProperty( xAxisProp, "AutoStepHelp" ) )
2888 mAny >>= bAutoStepHelp;
2890 if( !bAutoStepHelp && (GetProperty( xAxisProp, "StepHelp" ) ) )
2892 double dMinorUnit = 0;
2893 mAny >>= dMinorUnit;
2894 pFS->singleElement( FSNS( XML_c, XML_minorUnit ),
2895 XML_val, IS( dMinorUnit ),
2896 FSEND );
2899 if( nAxisType == XML_valAx && GetProperty( xAxisProp, "DisplayUnits" ) )
2901 bool bDisplayUnits = false;
2902 mAny >>= bDisplayUnits;
2903 if(bDisplayUnits)
2905 OUString aVal;
2906 if(GetProperty( xAxisProp, "BuiltInUnit" ))
2908 mAny >>= aVal;
2909 if(!aVal.isEmpty())
2911 pFS->startElement( FSNS( XML_c, XML_dispUnits ),
2912 FSEND );
2914 OString aBuiltInUnit = OUStringToOString(aVal, RTL_TEXTENCODING_UTF8);
2915 pFS->singleElement( FSNS( XML_c, XML_builtInUnit ),
2916 XML_val, aBuiltInUnit.getStr(),
2917 FSEND );
2919 pFS->singleElement(FSNS( XML_c, XML_dispUnitsLbl ),FSEND);
2920 pFS->endElement( FSNS( XML_c, XML_dispUnits ) );
2925 // TODO: text properties
2927 pFS->endElement( FSNS( XML_c, nAxisType ) );
2930 namespace {
2932 struct LabelPlacementParam
2934 bool mbExport;
2935 sal_Int32 meDefault;
2937 std::unordered_set<sal_Int32> maAllowedValues;
2939 LabelPlacementParam() :
2940 mbExport(true),
2941 meDefault(css::chart::DataLabelPlacement::OUTSIDE) {}
2943 void allowAll()
2945 maAllowedValues.insert(css::chart::DataLabelPlacement::OUTSIDE);
2946 maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
2947 maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
2948 maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
2949 maAllowedValues.insert(css::chart::DataLabelPlacement::TOP);
2950 maAllowedValues.insert(css::chart::DataLabelPlacement::BOTTOM);
2951 maAllowedValues.insert(css::chart::DataLabelPlacement::LEFT);
2952 maAllowedValues.insert(css::chart::DataLabelPlacement::RIGHT);
2953 maAllowedValues.insert(css::chart::DataLabelPlacement::AVOID_OVERLAP);
2957 const char* toOOXMLPlacement( sal_Int32 nPlacement )
2959 switch (nPlacement)
2961 case css::chart::DataLabelPlacement::OUTSIDE: return "outEnd";
2962 case css::chart::DataLabelPlacement::INSIDE: return "inEnd";
2963 case css::chart::DataLabelPlacement::CENTER: return "ctr";
2964 case css::chart::DataLabelPlacement::NEAR_ORIGIN: return "inBase";
2965 case css::chart::DataLabelPlacement::TOP: return "t";
2966 case css::chart::DataLabelPlacement::BOTTOM: return "b";
2967 case css::chart::DataLabelPlacement::LEFT: return "l";
2968 case css::chart::DataLabelPlacement::RIGHT: return "r";
2969 case css::chart::DataLabelPlacement::AVOID_OVERLAP: return "bestFit";
2970 default:
2974 return "outEnd";
2977 void writeLabelProperties(
2978 FSHelperPtr pFS, const uno::Reference<beans::XPropertySet>& xPropSet, const LabelPlacementParam& rLabelParam )
2980 if (!xPropSet.is())
2981 return;
2983 chart2::DataPointLabel aLabel;
2984 sal_Int32 nLabelBorderWidth = 0;
2985 sal_Int32 nLabelBorderColor = 0x00FFFFFF;
2987 xPropSet->getPropertyValue("Label") >>= aLabel;
2988 xPropSet->getPropertyValue("LabelBorderWidth") >>= nLabelBorderWidth;
2989 xPropSet->getPropertyValue("LabelBorderColor") >>= nLabelBorderColor;
2991 if (nLabelBorderWidth > 0)
2993 pFS->startElement(FSNS(XML_c, XML_spPr), FSEND);
2994 pFS->startElement(FSNS(XML_a, XML_ln), XML_w, IS(convertHmmToEmu(nLabelBorderWidth)), FSEND);
2995 if (nLabelBorderColor != -1)
2997 pFS->startElement(FSNS(XML_a, XML_solidFill), FSEND);
2999 OString aStr = OString::number(nLabelBorderColor, 16).toAsciiUpperCase();
3000 pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr.getStr(), FSEND);
3002 pFS->endElement(FSNS(XML_a, XML_solidFill));
3004 pFS->endElement(FSNS(XML_a, XML_ln));
3005 pFS->endElement(FSNS(XML_c, XML_spPr));
3008 if (rLabelParam.mbExport)
3010 sal_Int32 nLabelPlacement = rLabelParam.meDefault;
3011 if (xPropSet->getPropertyValue("LabelPlacement") >>= nLabelPlacement)
3013 if (!rLabelParam.maAllowedValues.count(nLabelPlacement))
3014 nLabelPlacement = rLabelParam.meDefault;
3015 pFS->singleElement(FSNS(XML_c, XML_dLblPos), XML_val, toOOXMLPlacement(nLabelPlacement), FSEND);
3019 pFS->singleElement(FSNS(XML_c, XML_showLegendKey), XML_val, BS(aLabel.ShowLegendSymbol), FSEND);
3020 pFS->singleElement(FSNS(XML_c, XML_showVal), XML_val, BS(aLabel.ShowNumber), FSEND);
3021 pFS->singleElement(FSNS(XML_c, XML_showCatName), XML_val, BS(aLabel.ShowCategoryName), FSEND);
3022 pFS->singleElement(FSNS(XML_c, XML_showSerName), XML_val, BS(false), FSEND);
3023 pFS->singleElement(FSNS(XML_c, XML_showPercent), XML_val, BS(aLabel.ShowNumberInPercent), FSEND);
3028 void ChartExport::exportDataLabels(
3029 const uno::Reference<chart2::XDataSeries> & xSeries, sal_Int32 nSeriesLength, sal_Int32 eChartType )
3031 if (!xSeries.is() || nSeriesLength <= 0)
3032 return;
3034 uno::Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
3035 if (!xPropSet.is())
3036 return;
3038 FSHelperPtr pFS = GetFS();
3039 pFS->startElement(FSNS(XML_c, XML_dLbls), FSEND);
3041 uno::Sequence<sal_Int32> aAttrLabelIndices;
3042 xPropSet->getPropertyValue("AttributedDataPoints") >>= aAttrLabelIndices;
3044 // We must not export label placement property when the chart type doesn't
3045 // support this option in MS Office, else MS Office would think the file
3046 // is corrupt & refuse to open it.
3048 const chart::TypeGroupInfo& rInfo = chart::GetTypeGroupInfo(static_cast<chart::TypeId>(eChartType));
3049 LabelPlacementParam aParam;
3050 aParam.mbExport = !mbIs3DChart;
3051 aParam.meDefault = rInfo.mnDefLabelPos;
3052 aParam.allowAll();
3053 switch (eChartType) // diagram chart type
3055 case chart::TYPEID_PIE:
3056 if(getChartType() == chart::TYPEID_DOUGHNUT)
3057 aParam.mbExport = false;
3058 else
3059 // All pie charts support label placement.
3060 aParam.mbExport = true;
3061 break;
3062 case chart::TYPEID_AREA:
3063 case chart::TYPEID_RADARLINE:
3064 case chart::TYPEID_RADARAREA:
3065 // These chart types don't support label placement.
3066 aParam.mbExport = false;
3067 break;
3068 case chart::TYPEID_BAR:
3069 if (mbStacked || mbPercent)
3071 aParam.maAllowedValues.clear();
3072 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3073 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3074 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3075 aParam.meDefault = css::chart::DataLabelPlacement::CENTER;
3077 else // Clustered bar chart
3079 aParam.maAllowedValues.clear();
3080 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3081 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3082 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::OUTSIDE);
3083 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3084 aParam.meDefault = css::chart::DataLabelPlacement::OUTSIDE;
3086 break;
3087 default:
3091 const sal_Int32* p = aAttrLabelIndices.getConstArray();
3092 const sal_Int32* pEnd = p + aAttrLabelIndices.getLength();
3093 for (; p != pEnd; ++p)
3095 sal_Int32 nIdx = *p;
3096 uno::Reference<beans::XPropertySet> xLabelPropSet = xSeries->getDataPointByIndex(nIdx);
3097 if (!xLabelPropSet.is())
3098 continue;
3100 // Individual label property that overwrites the baseline.
3101 pFS->startElement(FSNS(XML_c, XML_dLbl), FSEND);
3102 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, I32S(nIdx), FSEND);
3103 writeLabelProperties(pFS, xLabelPropSet, aParam);
3104 pFS->endElement(FSNS(XML_c, XML_dLbl));
3107 // Baseline label properties for all labels.
3108 writeLabelProperties(pFS, xPropSet, aParam);
3110 pFS->singleElement(FSNS(XML_c, XML_showLeaderLines),
3111 XML_val, "0",
3112 FSEND);
3114 pFS->endElement(FSNS(XML_c, XML_dLbls));
3117 void ChartExport::exportDataPoints(
3118 const uno::Reference< beans::XPropertySet > & xSeriesProperties,
3119 sal_Int32 nSeriesLength )
3121 uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
3122 bool bVaryColorsByPoint = false;
3123 Sequence< sal_Int32 > aDataPointSeq;
3124 if( xSeriesProperties.is())
3126 Any aAny = xSeriesProperties->getPropertyValue(
3127 OUString( "AttributedDataPoints" ));
3128 aAny >>= aDataPointSeq;
3129 xSeriesProperties->getPropertyValue(
3130 OUString( "VaryColorsByPoint" )) >>= bVaryColorsByPoint;
3133 const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
3134 sal_Int32 nElement;
3135 Reference< chart2::XColorScheme > xColorScheme;
3136 if( mxNewDiagram.is())
3137 xColorScheme.set( mxNewDiagram->getDefaultColorScheme());
3139 if( bVaryColorsByPoint && xColorScheme.is() )
3141 ::std::set< sal_Int32 > aAttrPointSet;
3142 ::std::copy( pPoints, pPoints + aDataPointSeq.getLength(),
3143 ::std::inserter( aAttrPointSet, aAttrPointSet.begin()));
3144 const ::std::set< sal_Int32 >::const_iterator aEndIt( aAttrPointSet.end());
3145 for( nElement = 0; nElement < nSeriesLength; ++nElement )
3147 uno::Reference< beans::XPropertySet > xPropSet;
3148 if( aAttrPointSet.find( nElement ) != aEndIt )
3152 xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3153 xSeries, nElement, getModel() );
3155 catch( const uno::Exception & rEx )
3157 SAL_WARN( "oox", "Exception caught during Export of data point: " << rEx.Message );
3160 else
3162 // property set only containing the color
3163 xPropSet.set( new ColorPropertySet( xColorScheme->getColorByIndex( nElement )));
3166 if( xPropSet.is() )
3168 FSHelperPtr pFS = GetFS();
3169 pFS->startElement( FSNS( XML_c, XML_dPt ),
3170 FSEND );
3171 pFS->singleElement( FSNS( XML_c, XML_idx ),
3172 XML_val, I32S(nElement),
3173 FSEND );
3174 exportShapeProps( xPropSet );
3176 pFS->endElement( FSNS( XML_c, XML_dPt ) );
3182 void ChartExport::exportAxesId( sal_Int32 nAttachedAxis )
3184 sal_Int32 nAxisIdx = lcl_generateRandomValue();
3185 sal_Int32 nAxisIdy = lcl_generateRandomValue();
3186 maAxes.push_back( AxisIdPair( AXIS_PRIMARY_X, nAxisIdx, nAxisIdy ) );
3187 maAxes.push_back( AxisIdPair( nAttachedAxis, nAxisIdy, nAxisIdx ) );
3188 FSHelperPtr pFS = GetFS();
3189 pFS->singleElement( FSNS( XML_c, XML_axId ),
3190 XML_val, I32S( nAxisIdx ),
3191 FSEND );
3192 pFS->singleElement( FSNS( XML_c, XML_axId ),
3193 XML_val, I32S( nAxisIdy ),
3194 FSEND );
3195 if( mbHasZAxis )
3197 sal_Int32 nAxisIdz = 0;
3198 if( isDeep3dChart() )
3200 nAxisIdz = lcl_generateRandomValue();
3201 maAxes.push_back( AxisIdPair( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy ) );
3203 pFS->singleElement( FSNS( XML_c, XML_axId ),
3204 XML_val, I32S( nAxisIdz ),
3205 FSEND );
3209 void ChartExport::exportGrouping( bool isBar )
3211 FSHelperPtr pFS = GetFS();
3212 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3213 // grouping
3214 if( GetProperty( xPropSet, "Stacked" ) )
3215 mAny >>= mbStacked;
3216 if( GetProperty( xPropSet, "Percent" ) )
3217 mAny >>= mbPercent;
3219 const char* grouping = NULL;
3220 if (mbStacked)
3221 grouping = "stacked";
3222 else if (mbPercent)
3223 grouping = "percentStacked";
3224 else
3226 if( isBar && !isDeep3dChart() )
3228 grouping = "clustered";
3230 else
3231 grouping = "standard";
3233 pFS->singleElement( FSNS( XML_c, XML_grouping ),
3234 XML_val, grouping,
3235 FSEND );
3238 void ChartExport::exportTrendlines( Reference< chart2::XDataSeries > xSeries )
3240 FSHelperPtr pFS = GetFS();
3241 Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, UNO_QUERY );
3242 if( xRegressionCurveContainer.is() )
3244 Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
3245 const Reference< chart2::XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
3246 const Reference< chart2::XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
3247 for( const Reference< chart2::XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
3249 Reference< chart2::XRegressionCurve > xRegCurve = *pIt;
3250 if (!xRegCurve.is())
3251 continue;
3253 Reference< XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
3255 OUString aService;
3256 Reference< lang::XServiceName > xServiceName( xProperties, UNO_QUERY );
3257 if( !xServiceName.is() )
3258 continue;
3260 aService = xServiceName->getServiceName();
3262 if(aService != "com.sun.star.chart2.LinearRegressionCurve" &&
3263 aService != "com.sun.star.chart2.ExponentialRegressionCurve" &&
3264 aService != "com.sun.star.chart2.LogarithmicRegressionCurve" &&
3265 aService != "com.sun.star.chart2.PotentialRegressionCurve" &&
3266 aService != "com.sun.star.chart2.PolynomialRegressionCurve" &&
3267 aService != "com.sun.star.chart2.MovingAverageRegressionCurve")
3268 continue;
3270 pFS->startElement( FSNS( XML_c, XML_trendline ), FSEND );
3272 OUString aName;
3273 xProperties->getPropertyValue("CurveName") >>= aName;
3274 if(!aName.isEmpty())
3276 pFS->startElement( FSNS( XML_c, XML_name), FSEND);
3277 pFS->writeEscaped(aName);
3278 pFS->endElement( FSNS( XML_c, XML_name) );
3281 exportShapeProps( xProperties );
3283 if( aService == "com.sun.star.chart2.LinearRegressionCurve" )
3285 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3286 XML_val, "linear",
3287 FSEND );
3289 else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
3291 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3292 XML_val, "exp",
3293 FSEND );
3295 else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
3297 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3298 XML_val, "log",
3299 FSEND );
3301 else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
3303 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3304 XML_val, "power",
3305 FSEND );
3307 else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
3309 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3310 XML_val, "poly",
3311 FSEND );
3313 sal_Int32 aDegree = 2;
3314 xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
3315 pFS->singleElement( FSNS( XML_c, XML_order ),
3316 XML_val, I32S(aDegree),
3317 FSEND );
3319 else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
3321 pFS->singleElement( FSNS( XML_c, XML_trendlineType ),
3322 XML_val, "movingAvg",
3323 FSEND );
3325 sal_Int32 aPeriod = 2;
3326 xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
3328 pFS->singleElement( FSNS( XML_c, XML_period ),
3329 XML_val, I32S(aPeriod),
3330 FSEND );
3332 else
3334 // should never happen
3335 // This would produce invalid OOXML files so we check earlier for the type
3336 assert(false);
3339 double fExtrapolateForward = 0.0;
3340 double fExtrapolateBackward = 0.0;
3342 xProperties->getPropertyValue("ExtrapolateForward") >>= fExtrapolateForward;
3343 xProperties->getPropertyValue("ExtrapolateBackward") >>= fExtrapolateBackward;
3345 pFS->singleElement( FSNS( XML_c, XML_forward ),
3346 XML_val, OString::number(fExtrapolateForward).getStr(),
3347 FSEND );
3349 pFS->singleElement( FSNS( XML_c, XML_backward ),
3350 XML_val, OString::number(fExtrapolateBackward).getStr(),
3351 FSEND );
3353 bool bForceIntercept = false;
3354 xProperties->getPropertyValue("ForceIntercept") >>= bForceIntercept;
3356 if (bForceIntercept)
3358 double fInterceptValue = 0.0;
3359 xProperties->getPropertyValue("InterceptValue") >>= fInterceptValue;
3361 pFS->singleElement( FSNS( XML_c, XML_intercept ),
3362 XML_val, OString::number(fInterceptValue).getStr(),
3363 FSEND );
3366 // Equation properties
3367 Reference< XPropertySet > xEquationProperties( xRegCurve->getEquationProperties() );
3369 // Show Equation
3370 bool bShowEquation = false;
3371 xEquationProperties->getPropertyValue("ShowEquation") >>= bShowEquation;
3373 // Show R^2
3374 bool bShowCorrelationCoefficient = false;
3375 xEquationProperties->getPropertyValue("ShowCorrelationCoefficient") >>= bShowCorrelationCoefficient;
3377 pFS->singleElement( FSNS( XML_c, XML_dispRSqr ),
3378 XML_val, bShowCorrelationCoefficient ? "1" : "0",
3379 FSEND );
3381 pFS->singleElement( FSNS( XML_c, XML_dispEq ),
3382 XML_val, bShowEquation ? "1" : "0",
3383 FSEND );
3385 pFS->endElement( FSNS( XML_c, XML_trendline ) );
3390 void ChartExport::exportMarker(Reference< chart2::XDataSeries > xSeries)
3392 Reference< XPropertySet > xPropSet( xSeries, uno::UNO_QUERY );
3393 chart2::Symbol aSymbol;
3394 if( GetProperty( xPropSet, "Symbol" ) )
3395 mAny >>= aSymbol;
3397 if(aSymbol.Style != chart2::SymbolStyle_STANDARD && aSymbol.Style != chart2::SymbolStyle_AUTO && aSymbol.Style != chart2::SymbolStyle_NONE)
3398 return;
3400 FSHelperPtr pFS = GetFS();
3401 pFS->startElement( FSNS( XML_c, XML_marker ),
3402 FSEND );
3404 sal_Int32 nSymbol = aSymbol.StandardSymbol;
3405 // TODO: more properties support for marker
3406 const char* pSymbolType = NULL;
3407 switch( nSymbol )
3409 case 0:
3410 pSymbolType = "square";
3411 break;
3412 case 1:
3413 pSymbolType = "diamond";
3414 break;
3415 case 2:
3416 case 3:
3417 case 4:
3418 case 5:
3419 pSymbolType = "triangle";
3420 break;
3421 case 8:
3422 pSymbolType = "circle";
3423 break;
3424 case 9:
3425 pSymbolType = "star";
3426 break;
3427 case 10:
3428 pSymbolType = "x"; // in MS office 2010 built in symbol marker 'X' is represented as 'x'
3429 break;
3430 case 11:
3431 pSymbolType = "plus";
3432 break;
3433 case 13:
3434 pSymbolType = "dash";
3435 break;
3436 default:
3437 pSymbolType = "square";
3438 break;
3441 bool bSkipFormatting = false;
3442 if (aSymbol.Style == chart2::SymbolStyle_NONE)
3444 bSkipFormatting = true;
3445 pSymbolType = "none";
3448 if( pSymbolType )
3450 pFS->singleElement( FSNS( XML_c, XML_symbol ),
3451 XML_val, pSymbolType,
3452 FSEND );
3455 if (!bSkipFormatting)
3457 awt::Size aSymbolSize = aSymbol.Size;
3458 sal_Int32 nSize = std::max( aSymbolSize.Width, aSymbolSize.Height );
3460 nSize = nSize/250.0*7.0 + 1; // just guessed based on some test cases,
3461 //the value is always 1 less than the actual value.
3462 nSize = std::min<sal_Int32>( 72, std::max<sal_Int32>( 2, nSize ) );
3463 pFS->singleElement( FSNS( XML_c, XML_size),
3464 XML_val, I32S(nSize),
3465 FSEND );
3467 pFS->startElement( FSNS( XML_c, XML_spPr ),
3468 FSEND );
3470 util::Color aColor = aSymbol.FillColor;
3471 if (GetProperty(xPropSet, "Color"))
3472 mAny >>= aColor;
3474 if (aColor == -1)
3476 pFS->singleElement(FSNS(XML_a, XML_noFill), FSEND);
3478 else
3479 WriteSolidFill(aColor);
3481 pFS->endElement( FSNS( XML_c, XML_spPr ) );
3484 pFS->endElement( FSNS( XML_c, XML_marker ) );
3487 void ChartExport::exportSmooth()
3489 FSHelperPtr pFS = GetFS();
3490 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY );
3491 sal_Int32 nSplineType = 0;
3492 if( GetProperty( xPropSet, "SplineType" ) )
3493 mAny >>= nSplineType;
3494 const char* pVal = nSplineType != 0 ? "1" : "0";
3495 pFS->singleElement( FSNS( XML_c, XML_smooth ),
3496 XML_val, pVal,
3497 FSEND );
3500 void ChartExport::exportFirstSliceAng( )
3502 FSHelperPtr pFS = GetFS();
3503 sal_Int32 nStartingAngle = 0;
3504 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3505 if( GetProperty( xPropSet, "StartingAngle" ) )
3506 mAny >>= nStartingAngle;
3508 // convert to ooxml angle
3509 nStartingAngle = (450 - nStartingAngle ) % 360;
3510 pFS->singleElement( FSNS( XML_c, XML_firstSliceAng ),
3511 XML_val, I32S( nStartingAngle ),
3512 FSEND );
3515 namespace {
3517 const char* getErrorBarStyle(sal_Int32 nErrorBarStyle)
3519 switch(nErrorBarStyle)
3521 case cssc::ErrorBarStyle::NONE:
3522 return NULL;
3523 case cssc::ErrorBarStyle::VARIANCE:
3524 break;
3525 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
3526 return "stdDev";
3527 case cssc::ErrorBarStyle::ABSOLUTE:
3528 return "fixedVal";
3529 case cssc::ErrorBarStyle::RELATIVE:
3530 return "percentage";
3531 case cssc::ErrorBarStyle::ERROR_MARGIN:
3532 break;
3533 case cssc::ErrorBarStyle::STANDARD_ERROR:
3534 return "stdErr";
3535 case cssc::ErrorBarStyle::FROM_DATA:
3536 return "cust";
3537 default:
3538 assert(false && "can't happen");
3540 return NULL;
3543 Reference< chart2::data::XDataSequence> getLabeledSequence(
3544 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences,
3545 bool bPositive )
3547 const OUString aRolePrefix( "error-bars" );
3548 OUString aDirection;
3549 if(bPositive)
3550 aDirection = "positive";
3551 else
3552 aDirection = "negative";
3554 for( sal_Int32 nI=0; nI< aSequences.getLength(); ++nI )
3556 if( aSequences[nI].is())
3558 uno::Reference< chart2::data::XDataSequence > xSequence( aSequences[nI]->getValues());
3559 uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
3560 OUString aRole;
3561 if( ( xSeqProp->getPropertyValue(
3562 OUString( "Role" )) >>= aRole ) &&
3563 aRole.match( aRolePrefix ) && aRole.indexOf(aDirection) >= 0 )
3565 return xSequence;
3570 return Reference< chart2::data::XDataSequence > ();
3575 void ChartExport::exportErrorBar(Reference< XPropertySet> xErrorBarProps, bool bYError)
3577 sal_Int32 nErrorBarStyle = cssc::ErrorBarStyle::NONE;
3578 xErrorBarProps->getPropertyValue("ErrorBarStyle") >>= nErrorBarStyle;
3579 const char* pErrorBarStyle = getErrorBarStyle(nErrorBarStyle);
3580 if(!pErrorBarStyle)
3581 return;
3583 FSHelperPtr pFS = GetFS();
3584 pFS->startElement( FSNS( XML_c, XML_errBars ),
3585 FSEND );
3586 pFS->singleElement( FSNS( XML_c, XML_errDir ),
3587 XML_val, bYError ? "y" : "x",
3588 FSEND );
3589 bool bPositive = false, bNegative = false;
3590 xErrorBarProps->getPropertyValue("ShowPositiveError") >>= bPositive;
3591 xErrorBarProps->getPropertyValue("ShowNegativeError") >>= bNegative;
3592 const char* pErrBarType;
3593 if(bPositive && bNegative)
3594 pErrBarType = "both";
3595 else if(bPositive)
3596 pErrBarType = "plus";
3597 else if(bNegative)
3598 pErrBarType = "minus";
3599 else
3601 // what the hell should we do now?
3602 // at least this makes the file valid
3603 pErrBarType = "both";
3605 pFS->singleElement( FSNS( XML_c, XML_errBarType ),
3606 XML_val, pErrBarType,
3607 FSEND );
3608 pFS->singleElement( FSNS( XML_c, XML_errValType ),
3609 XML_val, pErrorBarStyle,
3610 FSEND );
3611 pFS->singleElement( FSNS( XML_c, XML_noEndCap ),
3612 XML_val, "0",
3613 FSEND );
3614 if(nErrorBarStyle == cssc::ErrorBarStyle::FROM_DATA)
3616 uno::Reference< chart2::data::XDataSource > xDataSource(xErrorBarProps, uno::UNO_QUERY);
3617 Sequence< Reference < chart2::data::XLabeledDataSequence > > aSequences =
3618 xDataSource->getDataSequences();
3620 if(bPositive)
3622 exportSeriesValues(getLabeledSequence(aSequences, true), XML_plus);
3625 if(bNegative)
3627 exportSeriesValues(getLabeledSequence(aSequences, false), XML_minus);
3630 else
3632 double nVal = 0.0;
3633 if(nErrorBarStyle == cssc::ErrorBarStyle::STANDARD_DEVIATION)
3635 xErrorBarProps->getPropertyValue("Weight") >>= nVal;
3637 else
3639 if(bPositive)
3640 xErrorBarProps->getPropertyValue("PositiveError") >>= nVal;
3641 else
3642 xErrorBarProps->getPropertyValue("NegativeError") >>= nVal;
3645 OString aVal = OString::number(nVal);
3647 pFS->singleElement( FSNS( XML_c, XML_val ),
3648 XML_val, aVal.getStr(),
3649 FSEND );
3652 pFS->endElement( FSNS( XML_c, XML_errBars) );
3655 void ChartExport::exportView3D()
3657 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3658 if( !xPropSet.is() )
3659 return;
3660 FSHelperPtr pFS = GetFS();
3661 pFS->startElement( FSNS( XML_c, XML_view3D ),
3662 FSEND );
3663 sal_Int32 eChartType = getChartType( );
3664 // rotX
3665 if( GetProperty( xPropSet, "RotationHorizontal" ) )
3667 sal_Int32 nRotationX = 0;
3668 mAny >>= nRotationX;
3669 if( nRotationX < 0 )
3671 if(eChartType == chart::TYPEID_PIE)
3673 /* In OOXML we get value in 0..90 range for pie chart X rotation , whereas we expect it to be in -90..90 range,
3674 so we conver that during import. It is modified in View3DConverter::convertFromModel()
3675 here we convert it back to 0..90 as we received in import */
3676 nRotationX += 90; // X rotation (map Chart2 [-179,180] to OOXML [0..90])
3678 else
3679 nRotationX += 360; // X rotation (map Chart2 [-179,180] to OOXML [-90..90])
3681 pFS->singleElement( FSNS( XML_c, XML_rotX ),
3682 XML_val, I32S( nRotationX ),
3683 FSEND );
3685 // rotY
3686 if( GetProperty( xPropSet, "RotationVertical" ) )
3688 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
3689 if( eChartType == chart::TYPEID_PIE && GetProperty( xPropSet, "StartingAngle" ) )
3691 // Y rotation used as 'first pie slice angle' in 3D pie charts
3692 sal_Int32 nStartingAngle=0;
3693 mAny >>= nStartingAngle;
3694 // convert to ooxml angle
3695 nStartingAngle = (450 - nStartingAngle ) % 360;
3696 pFS->singleElement( FSNS( XML_c, XML_rotY ),
3697 XML_val, I32S( nStartingAngle ),
3698 FSEND );
3700 else
3702 sal_Int32 nRotationY = 0;
3703 mAny >>= nRotationY;
3704 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
3705 if( nRotationY < 0 )
3706 nRotationY += 360;
3707 pFS->singleElement( FSNS( XML_c, XML_rotY ),
3708 XML_val, I32S( nRotationY ),
3709 FSEND );
3712 // rAngAx
3713 if( GetProperty( xPropSet, "RightAngledAxes" ) )
3715 bool bRightAngled = false;
3716 mAny >>= bRightAngled;
3717 const char* sRightAngled = bRightAngled ? "1":"0";
3718 pFS->singleElement( FSNS( XML_c, XML_rAngAx ),
3719 XML_val, sRightAngled,
3720 FSEND );
3722 // perspective
3723 if( GetProperty( xPropSet, "Perspective" ) )
3725 sal_Int32 nPerspective = 0;
3726 mAny >>= nPerspective;
3727 // map Chart2 [0,100] to OOXML [0..200]
3728 nPerspective *= 2;
3729 pFS->singleElement( FSNS( XML_c, XML_perspective ),
3730 XML_val, I32S( nPerspective ),
3731 FSEND );
3733 pFS->endElement( FSNS( XML_c, XML_view3D ) );
3736 bool ChartExport::isDeep3dChart()
3738 bool isDeep = false;
3739 if( mbIs3DChart )
3741 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
3742 if( GetProperty( xPropSet, "Deep" ) )
3743 mAny >>= isDeep;
3745 return isDeep;
3748 OUString ChartExport::getNumberFormatCode(sal_Int32 nKey) const
3750 uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(mxChartModel, uno::UNO_QUERY_THROW);
3751 uno::Reference<util::XNumberFormats> xNumberFormats = xNumberFormatsSupplier->getNumberFormats();
3752 uno::Reference<beans::XPropertySet> xNumberFormat = xNumberFormats->getByKey(nKey);
3754 if (!xNumberFormat.is())
3755 return OUString();
3757 uno::Any aAny = xNumberFormat->getPropertyValue("FormatString");
3758 OUString aValue;
3759 aAny >>= aValue;
3760 return aValue;
3763 }// drawingml
3764 }// oox
3766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */