LibreOffice Module oox (master) 1
chartexport.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <oox/token/namespaces.hxx>
21#include <oox/token/properties.hxx>
22#include <oox/token/tokens.hxx>
26#include <oox/export/utils.hxx>
28
29#include <cstdio>
30#include <limits>
31
32#include <com/sun/star/awt/Gradient.hpp>
33#include <com/sun/star/chart/XChartDocument.hpp>
34#include <com/sun/star/chart/ChartLegendPosition.hpp>
35#include <com/sun/star/chart/XTwoAxisXSupplier.hpp>
36#include <com/sun/star/chart/XTwoAxisYSupplier.hpp>
37#include <com/sun/star/chart/XAxisZSupplier.hpp>
38#include <com/sun/star/chart/ChartDataRowSource.hpp>
39#include <com/sun/star/chart/X3DDisplay.hpp>
40#include <com/sun/star/chart/XStatisticDisplay.hpp>
41#include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
42#include <com/sun/star/chart/ChartSymbolType.hpp>
43#include <com/sun/star/chart/ChartAxisMarks.hpp>
44#include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
45#include <com/sun/star/chart/ChartAxisPosition.hpp>
46#include <com/sun/star/chart/ChartSolidType.hpp>
47#include <com/sun/star/chart/DataLabelPlacement.hpp>
48#include <com/sun/star/chart/ErrorBarStyle.hpp>
49#include <com/sun/star/chart/MissingValueTreatment.hpp>
50#include <com/sun/star/chart/XDiagramPositioning.hpp>
51#include <com/sun/star/chart/TimeIncrement.hpp>
52#include <com/sun/star/chart/TimeInterval.hpp>
53#include <com/sun/star/chart/TimeUnit.hpp>
54
55#include <com/sun/star/chart2/RelativePosition.hpp>
56#include <com/sun/star/chart2/RelativeSize.hpp>
57#include <com/sun/star/chart2/XChartDocument.hpp>
58#include <com/sun/star/chart2/XDiagram.hpp>
59#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
60#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
61#include <com/sun/star/chart2/XChartTypeContainer.hpp>
62#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
63#include <com/sun/star/chart2/DataPointLabel.hpp>
64#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
65#include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
66#include <com/sun/star/chart2/Symbol.hpp>
67#include <com/sun/star/chart2/data/XDataSource.hpp>
68#include <com/sun/star/chart2/data/XDataProvider.hpp>
69#include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
70#include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
71#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
72#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
73#include <com/sun/star/chart2/AxisType.hpp>
74
75#include <com/sun/star/beans/XPropertySet.hpp>
76#include <com/sun/star/container/XNameAccess.hpp>
77#include <com/sun/star/drawing/XShape.hpp>
78#include <com/sun/star/drawing/XShapes.hpp>
79#include <com/sun/star/drawing/FillStyle.hpp>
80#include <com/sun/star/drawing/LineStyle.hpp>
81#include <com/sun/star/awt/XBitmap.hpp>
82#include <com/sun/star/lang/XMultiServiceFactory.hpp>
83#include <com/sun/star/lang/XServiceName.hpp>
84
85#include <com/sun/star/table/CellAddress.hpp>
86#include <com/sun/star/sheet/XFormulaParser.hpp>
87#include <com/sun/star/sheet/FormulaToken.hpp>
88#include <com/sun/star/sheet/AddressConvention.hpp>
89
90#include <com/sun/star/container/XNamed.hpp>
91#include <com/sun/star/embed/XVisualObject.hpp>
92#include <com/sun/star/embed/Aspects.hpp>
93
95#include <comphelper/random.hxx>
96#include <utility>
98#include "ColorPropertySet.hxx"
99
100#include <svl/numformat.hxx>
101#include <svl/numuno.hxx>
103#include <sal/log.hxx>
104
105#include <set>
106#include <unordered_set>
107
108#include <o3tl/temporary.hxx>
109#include <o3tl/sorted_vector.hxx>
110
111using namespace css;
112using namespace css::uno;
113using namespace css::drawing;
114using namespace ::oox::core;
115using css::beans::PropertyValue;
116using css::beans::XPropertySet;
117using css::container::XNamed;
118using css::table::CellAddress;
119using css::sheet::XFormulaParser;
120using ::oox::core::XmlFilterBase;
121using ::sax_fastparser::FSHelperPtr;
122
123namespace cssc = css::chart;
124
125namespace oox::drawingml {
126
127namespace {
128
129bool isPrimaryAxes(sal_Int32 nIndex)
130{
131 assert(nIndex == 0 || nIndex == 1);
132 return nIndex != 1;
133}
134
135class lcl_MatchesRole
136{
137public:
138 explicit lcl_MatchesRole( OUString aRole ) :
139 m_aRole(std::move( aRole ))
140 {}
141
142 bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
143 {
144 if( !xSeq.is() )
145 return false;
146 Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
147 OUString aRole;
148
149 return ( xProp.is() &&
150 (xProp->getPropertyValue( "Role" ) >>= aRole ) &&
151 m_aRole == aRole );
152 }
153
154private:
155 OUString m_aRole;
156};
157
158}
159
161{
162 bHasDateCategories = false;
164 try
165 {
167 xDiagram, uno::UNO_QUERY_THROW );
169 xCooSysCnt->getCoordinateSystems());
170 for( const auto& xCooSys : aCooSysSeq )
171 {
172 OSL_ASSERT( xCooSys.is());
173 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
174 {
175 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
176 for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
177 {
178 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI );
179 OSL_ASSERT( xAxis.is());
180 if( xAxis.is())
181 {
182 chart2::ScaleData aScaleData = xAxis->getScaleData();
183 if( aScaleData.Categories.is())
184 {
185 bHasDateCategories = aScaleData.AxisType == chart2::AxisType::DATE;
186 xResult.set( aScaleData.Categories );
187 break;
188 }
189 }
190 }
191 }
192 }
193 }
194 catch( const uno::Exception & )
195 {
197 }
198
199 return xResult;
200}
201
202static Reference< chart2::data::XLabeledDataSequence >
205 const OUString & rRole )
206{
208
209 const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
210 const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
212 ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole ));
213
214 if( pMatch != pEnd )
215 return *pMatch;
216
217 return aNoResult;
218}
219
221{
222 //categories are always the first sequence
223 Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
224 bool bDateCategories;
225 Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram, bDateCategories ) );
226 return xCategories.is();
227}
228
230{
231 bool bCategoryPositionShifted = false;
232 try
233 {
235 xDiagram, uno::UNO_QUERY_THROW);
237 xCooSysCnt->getCoordinateSystems());
238 for (const auto& xCooSys : aCooSysSeq)
239 {
240 OSL_ASSERT(xCooSys.is());
241 if( 0 < xCooSys->getDimension() && 0 <= xCooSys->getMaximumAxisIndexByDimension(0) )
242 {
243 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension(0, 0);
244 OSL_ASSERT(xAxis.is());
245 if (xAxis.is())
246 {
247 chart2::ScaleData aScaleData = xAxis->getScaleData();
248 bCategoryPositionShifted = aScaleData.ShiftedCategoryPosition;
249 break;
250 }
251 }
252 }
253 }
254 catch (const uno::Exception&)
255 {
257 }
258
259 return bCategoryPositionShifted;
260}
261
262static sal_Int32 lcl_getCategoryAxisType( const Reference< chart2::XDiagram >& xDiagram, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
263{
264 sal_Int32 nAxisType = -1;
265 try
266 {
268 xDiagram, uno::UNO_QUERY_THROW);
270 xCooSysCnt->getCoordinateSystems());
271 for( const auto& xCooSys : aCooSysSeq )
272 {
273 OSL_ASSERT(xCooSys.is());
274 if( nDimensionIndex < xCooSys->getDimension() && nAxisIndex <= xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex) )
275 {
276 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension(nDimensionIndex, nAxisIndex);
277 OSL_ASSERT(xAxis.is());
278 if( xAxis.is() )
279 {
280 chart2::ScaleData aScaleData = xAxis->getScaleData();
281 nAxisType = aScaleData.AxisType;
282 break;
283 }
284 }
285 }
286 }
287 catch (const uno::Exception&)
288 {
290 }
291
292 return nAxisType;
293}
294
295static OUString lclGetTimeUnitToken( sal_Int32 nTimeUnit )
296{
297 switch( nTimeUnit )
298 {
299 case cssc::TimeUnit::DAY: return "days";
300 case cssc::TimeUnit::MONTH: return "months";
301 case cssc::TimeUnit::YEAR: return "years";
302 default: OSL_ENSURE(false, "lclGetTimeUnitToken - unexpected time unit");
303 }
304 return "days";
305}
306
307static cssc::TimeIncrement lcl_getDateTimeIncrement( const Reference< chart2::XDiagram >& xDiagram, sal_Int32 nAxisIndex )
308{
309 cssc::TimeIncrement aTimeIncrement;
310 try
311 {
313 xDiagram, uno::UNO_QUERY_THROW);
315 xCooSysCnt->getCoordinateSystems());
316 for( const auto& xCooSys : aCooSysSeq )
317 {
318 OSL_ASSERT(xCooSys.is());
319 if( 0 < xCooSys->getDimension() && nAxisIndex <= xCooSys->getMaximumAxisIndexByDimension(0) )
320 {
321 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension(0, nAxisIndex);
322 OSL_ASSERT(xAxis.is());
323 if( xAxis.is() )
324 {
325 chart2::ScaleData aScaleData = xAxis->getScaleData();
326 aTimeIncrement = aScaleData.TimeIncrement;
327 break;
328 }
329 }
330 }
331 }
332 catch (const uno::Exception&)
333 {
335 }
336
337 return aTimeIncrement;
338}
339
341 const Reference< chart2::XDataSeries > & xDataSeries )
342{
343 bool bResult=true;
344
345 try
346 {
347 sal_Int32 nAxisIndex = 0;
348 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
349 xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex;
350 bResult = (0==nAxisIndex);
351 }
352 catch( const uno::Exception & )
353 {
355 }
356
357 return bResult;
358}
359
360static OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
361{
362 OUStringBuffer aResult;
363 bool bPrecedeWithSpace = false;
364 for( const auto& rString : rSequence )
365 {
366 if( !rString.isEmpty())
367 {
368 if( bPrecedeWithSpace )
369 aResult.append( ' ' );
370 aResult.append( rString );
371 bPrecedeWithSpace = true;
372 }
373 }
374 return aResult.makeStringAndClear();
375}
376
378{
379 Sequence< OUString > aLabels;
380
381 uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY );
382 if( xTextualDataSequence.is())
383 {
384 aLabels = xTextualDataSequence->getTextualData();
385 }
386 else if( xLabelSeq.is())
387 {
388 const Sequence< uno::Any > aAnies( xLabelSeq->getData());
389 aLabels.realloc( aAnies.getLength());
390 auto pLabels = aLabels.getArray();
391 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
392 aAnies[i] >>= pLabels[i];
393 }
394
395 return aLabels;
396}
397
400 ::std::vector< OUString > & rOutCategories )
401{
402 OSL_ASSERT( xCategories.is());
403 if( !xCategories.is())
404 return;
405 Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xCategories, uno::UNO_QUERY );
406 if( xTextualDataSequence.is())
407 {
408 rOutCategories.clear();
409 const Sequence< OUString > aTextData( xTextualDataSequence->getTextualData());
410 rOutCategories.insert( rOutCategories.end(), aTextData.begin(), aTextData.end() );
411 }
412 else
413 {
414 Sequence< uno::Any > aAnies( xCategories->getData());
415 rOutCategories.resize( aAnies.getLength());
416 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
417 aAnies[i] >>= rOutCategories[i];
418 }
419}
420
421static ::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq )
422{
423 ::std::vector< double > aResult;
424
425 Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
426 if( xNumSeq.is())
427 {
428 const Sequence< double > aValues( xNumSeq->getNumericalData());
429 aResult.insert( aResult.end(), aValues.begin(), aValues.end() );
430 }
431 else if( xSeq.is())
432 {
433 Sequence< uno::Any > aAnies( xSeq->getData());
434 aResult.resize( aAnies.getLength(), std::numeric_limits<double>::quiet_NaN() );
435 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
436 aAnies[i] >>= aResult[i];
437 }
438 return aResult;
439}
440
441static sal_Int32 lcl_getChartType( std::u16string_view sChartType )
442{
444 if( sChartType == u"com.sun.star.chart.BarDiagram"
445 || sChartType == u"com.sun.star.chart2.ColumnChartType" )
446 eChartTypeId = chart::TYPEID_BAR;
447 else if( sChartType == u"com.sun.star.chart.AreaDiagram"
448 || sChartType == u"com.sun.star.chart2.AreaChartType" )
449 eChartTypeId = chart::TYPEID_AREA;
450 else if( sChartType == u"com.sun.star.chart.LineDiagram"
451 || sChartType == u"com.sun.star.chart2.LineChartType" )
452 eChartTypeId = chart::TYPEID_LINE;
453 else if( sChartType == u"com.sun.star.chart.PieDiagram"
454 || sChartType == u"com.sun.star.chart2.PieChartType" )
455 eChartTypeId = chart::TYPEID_PIE;
456 else if( sChartType == u"com.sun.star.chart.DonutDiagram"
457 || sChartType == u"com.sun.star.chart2.DonutChartType" )
458 eChartTypeId = chart::TYPEID_DOUGHNUT;
459 else if( sChartType == u"com.sun.star.chart.XYDiagram"
460 || sChartType == u"com.sun.star.chart2.ScatterChartType" )
461 eChartTypeId = chart::TYPEID_SCATTER;
462 else if( sChartType == u"com.sun.star.chart.NetDiagram"
463 || sChartType == u"com.sun.star.chart2.NetChartType" )
464 eChartTypeId = chart::TYPEID_RADARLINE;
465 else if( sChartType == u"com.sun.star.chart.FilledNetDiagram"
466 || sChartType == u"com.sun.star.chart2.FilledNetChartType" )
467 eChartTypeId = chart::TYPEID_RADARAREA;
468 else if( sChartType == u"com.sun.star.chart.StockDiagram"
469 || sChartType == u"com.sun.star.chart2.CandleStickChartType" )
470 eChartTypeId = chart::TYPEID_STOCK;
471 else if( sChartType == u"com.sun.star.chart.BubbleDiagram"
472 || sChartType == u"com.sun.star.chart2.BubbleChartType" )
473 eChartTypeId = chart::TYPEID_BUBBLE;
474
475 return eChartTypeId;
476}
477
478static sal_Int32 lcl_generateRandomValue()
479{
480 return comphelper::rng::uniform_int_distribution(0, 100000000-1);
481}
482
483static sal_Int32 lcl_getAlphaFromTransparenceGradient(const awt::Gradient& rGradient, bool bStart)
484{
485 // Our alpha is a gray color value.
486 sal_uInt8 nRed = ::Color(ColorTransparency, bStart ? rGradient.StartColor : rGradient.EndColor).GetRed();
487 // drawingML alpha is a percentage on a 0..100000 scale.
488 return (255 - nRed) * oox::drawingml::MAX_PERCENT / 255;
489}
490
492{
493 return maLabels.empty();
494}
495
497{
498 return maLabels.size();
499}
500
501bool DataLabelsRange::hasLabel(sal_Int32 nIndex) const
502{
503 return maLabels.find(nIndex) != maLabels.end();
504}
505
506const OUString & DataLabelsRange::getRange() const
507{
508 return maRange;
509}
510
511void DataLabelsRange::setRange(const OUString& rRange)
512{
513 maRange = rRange;
514}
515
516void DataLabelsRange::setLabel(sal_Int32 nIndex, const OUString& rText)
517{
518 maLabels.emplace(nIndex, rText);
519}
520
521DataLabelsRange::LabelsRangeMap::const_iterator DataLabelsRange::begin() const
522{
523 return maLabels.begin();
524}
525
526DataLabelsRange::LabelsRangeMap::const_iterator DataLabelsRange::end() const
527{
528 return maLabels.end();
529}
530
531ChartExport::ChartExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, Reference< frame::XModel > const & xModel, XmlFilterBase* pFB, DocumentType eDocumentType )
532 : DrawingML( std::move(pFS), pFB, eDocumentType )
533 , mnXmlNamespace( nXmlNamespace )
534 , mnSeriesCount(0)
535 , mxChartModel( xModel )
536 , mpURLTransformer(std::make_shared<URLTransformer>())
537 , mbHasCategoryLabels( false )
538 , mbHasZAxis( false )
539 , mbIs3DChart( false )
540 , mbStacked(false)
541 , mbPercent(false)
542 , mbHasDateCategories(false)
543{
544}
545
546void ChartExport::SetURLTranslator(const std::shared_ptr<URLTransformer>& pTransformer)
547{
548 mpURLTransformer = pTransformer;
549}
550
552{
553 OUString sChartType = mxDiagram->getDiagramType();
554 return lcl_getChartType( sChartType );
555}
556
557namespace {
558
559uno::Sequence< beans::PropertyValue > createArguments(
560 const OUString & rRangeRepresentation, bool bUseColumns)
561{
562 css::chart::ChartDataRowSource eRowSource = css::chart::ChartDataRowSource_ROWS;
563 if (bUseColumns)
564 eRowSource = css::chart::ChartDataRowSource_COLUMNS;
565
566 uno::Sequence<beans::PropertyValue> aArguments{
567 { "DataRowSource", -1, uno::Any(eRowSource), beans::PropertyState_DIRECT_VALUE },
568 { "FirstCellAsLabel", -1, uno::Any(false), beans::PropertyState_DIRECT_VALUE },
569 { "HasCategories", -1, uno::Any(false), beans::PropertyState_DIRECT_VALUE },
570 { "CellRangeRepresentation", -1, uno::Any(rRangeRepresentation),
571 beans::PropertyState_DIRECT_VALUE }
572 };
573
574 return aArguments;
575}
576
577Reference<chart2::XDataSeries> getPrimaryDataSeries(const Reference<chart2::XChartType>& xChartType)
578{
579 Reference< chart2::XDataSeriesContainer > xDSCnt(xChartType, uno::UNO_QUERY_THROW);
580
581 // export dataseries for current chart-type
582 const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq(xDSCnt->getDataSeries());
583 for (const auto& rSeries : aSeriesSeq)
584 {
585 Reference<chart2::XDataSeries> xSource(rSeries, uno::UNO_QUERY);
586 if (xSource.is())
587 return xSource;
588 }
589
590 return Reference<chart2::XDataSeries>();
591}
592
593}
594
596{
597 Reference< chart2::XChartDocument > xChartDoc(getModel(), uno::UNO_QUERY);
598 OSL_ASSERT(xChartDoc.is());
599 if (xChartDoc.is())
600 {
601 Reference< chart2::data::XDataProvider > xDataProvider(xChartDoc->getDataProvider());
602 OSL_ENSURE(xDataProvider.is(), "No DataProvider");
603 if (xDataProvider.is())
604 {
605 //detect whether the first series is a row or a column
606 bool bSeriesUsesColumns = true;
607 Reference< chart2::XDiagram > xDiagram(xChartDoc->getFirstDiagram());
608 try
609 {
610 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(xDiagram, uno::UNO_QUERY_THROW);
611 const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(xCooSysCnt->getCoordinateSystems());
612 for (const auto& rCooSys : aCooSysSeq)
613 {
614 const Reference< chart2::XChartTypeContainer > xCTCnt(rCooSys, uno::UNO_QUERY_THROW);
615 const Sequence< Reference< chart2::XChartType > > aChartTypeSeq(xCTCnt->getChartTypes());
616 for (const auto& rChartType : aChartTypeSeq)
617 {
618 Reference< chart2::XDataSeries > xDataSeries = getPrimaryDataSeries(rChartType);
619 if (xDataSeries.is())
620 {
621 uno::Reference< chart2::data::XDataSource > xSeriesSource(xDataSeries, uno::UNO_QUERY);
622 const uno::Sequence< beans::PropertyValue > rArguments = xDataProvider->detectArguments(xSeriesSource);
623 for (const beans::PropertyValue& rProperty : rArguments)
624 {
625 if (rProperty.Name == "DataRowSource")
626 {
627 css::chart::ChartDataRowSource eRowSource;
628 if (rProperty.Value >>= eRowSource)
629 {
630 bSeriesUsesColumns = (eRowSource == css::chart::ChartDataRowSource_COLUMNS);
631 break;
632 }
633 }
634 }
635 }
636 }
637 }
638 }
639 catch (const uno::Exception &)
640 {
641 DBG_UNHANDLED_EXCEPTION("chart2");
642 }
643 // detect we have an inner data table or not
644 if (xChartDoc->hasInternalDataProvider() && rRange == "categories")
645 {
646 try
647 {
648 css::uno::Reference< css::chart2::XAnyDescriptionAccess > xDataAccess(xChartDoc->getDataProvider(), uno::UNO_QUERY);
649 const Sequence< Sequence< uno::Any > >aAnyCategories(bSeriesUsesColumns ? xDataAccess->getAnyRowDescriptions() : xDataAccess->getAnyColumnDescriptions());
650 auto pMax = std::max_element(aAnyCategories.begin(), aAnyCategories.end(),
651 [](const Sequence<uno::Any>& a, const Sequence<uno::Any>& b) {
652 return a.getLength() < b.getLength(); });
653
654 //minimum is 1!
655 if (pMax != aAnyCategories.end() && pMax->getLength() > 1)
656 {
657 sal_Int32 nLevelCount = pMax->getLength();
658 //we have complex categories
659 //sort the categories name
660 Sequence<Sequence<OUString>>aFinalSplitSource(nLevelCount);
661 auto pFinalSplitSource = aFinalSplitSource.getArray();
662 for (sal_Int32 i = 0; i < nLevelCount; i++)
663 {
664 sal_Int32 nElemLabel = 0;
665 pFinalSplitSource[nLevelCount - i - 1].realloc(aAnyCategories.getLength());
666 auto pSeq = pFinalSplitSource[nLevelCount - i - 1].getArray();
667 for (auto const& elemLabel : aAnyCategories)
668 {
669 // make sure elemLabel[i] exists!
670 if (elemLabel.getLength() > i)
671 {
672 pSeq[nElemLabel] = elemLabel[i].get<OUString>();
673 nElemLabel++;
674 }
675 }
676 }
677 return aFinalSplitSource;
678 }
679 }
680 catch (const uno::Exception &)
681 {
683 }
684 }
685 else
686 {
687 try
688 {
689 uno::Reference< chart2::data::XDataSource > xCategoriesSource(xDataProvider->createDataSource(
690 createArguments(rRange, bSeriesUsesColumns)));
691
692 if (xCategoriesSource.is())
693 {
694 const Sequence< Reference< chart2::data::XLabeledDataSequence >> aCategories = xCategoriesSource->getDataSequences();
695 if (aCategories.getLength() > 1)
696 {
697 //we have complex categories
698 //sort the categories name
699 Sequence<Sequence<OUString>> aFinalSplitSource(aCategories.getLength());
700 std::transform(aCategories.begin(), aCategories.end(),
701 std::reverse_iterator(asNonConstRange(aFinalSplitSource).end()),
703 return lcl_getLabelSequence(xCat->getValues()); });
704 return aFinalSplitSource;
705 }
706 }
707 }
708 catch (const uno::Exception &)
709 {
711 }
712 }
713 }
714 }
715
717}
718
719OUString ChartExport::parseFormula( const OUString& rRange )
720{
721 OUString aResult;
723 uno::Reference< lang::XMultiServiceFactory > xSF = GetFB()->getModelFactory();
724 if( xSF.is() )
725 {
726 try
727 {
728 xParser.set( xSF->createInstance("com.sun.star.sheet.FormulaParser"), UNO_QUERY );
729 }
730 catch( Exception& )
731 {
732 }
733 }
734
735 SAL_WARN_IF(!xParser.is(), "oox", "creating formula parser failed");
736
737 if( xParser.is() )
738 {
739 Reference< XPropertySet > xParserProps( xParser, uno::UNO_QUERY );
740 // rRange is the result of a
741 // css::chart2::data::XDataSequence::getSourceRangeRepresentation()
742 // call that returns the range in the document's current UI notation.
743 // Creating a FormulaParser defaults to the same notation, for
744 // parseFormula() do not attempt to override the FormulaConvention
745 // property with css::sheet::AddressConvention::OOO or some such.
746 /* TODO: it would be much better to introduce a
747 * getSourceRangeRepresentation(css::sheet::AddressConvention) to
748 * return the ranges in a specific convention than converting them with
749 * the overhead of creating an XFormulaParser for each... */
750 uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( rRange, CellAddress( 0, 0, 0 ) );
751 if( xParserProps.is() )
752 {
753 xParserProps->setPropertyValue("FormulaConvention", uno::Any(css::sheet::AddressConvention::XL_OOX) );
754 // For referencing named ranges correctly with special excel chart syntax.
755 xParserProps->setPropertyValue("RefConventionChartOOXML", uno::Any(true) );
756 }
757 aResult = xParser->printFormula( aTokens, CellAddress( 0, 0, 0 ) );
758 }
759 else
760 {
761 //FIXME: currently just using simple converter, e.g $Sheet1.$A$1:$C$1 -> Sheet1!$A$1:$C$1
762 OUString aRange( rRange );
763 if( aRange.startsWith("$") )
764 aRange = aRange.copy(1);
765 aRange = aRange.replaceAll(".$", "!$" );
766 aResult = aRange;
767 }
768
769 return aResult;
770}
771
772void ChartExport::WriteChartObj( const Reference< XShape >& xShape, sal_Int32 nID, sal_Int32 nChartCount )
773{
774 FSHelperPtr pFS = GetFS();
775
776 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
777
778 pFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
779
780 pFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
781
782 // TODO: get the correct chart name chart id
783 OUString sName = "Object 1";
784 Reference< XNamed > xNamed( xShape, UNO_QUERY );
785 if (xNamed.is())
786 sName = xNamed->getName();
787
788 pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
789 XML_id, OString::number(nID),
790 XML_name, sName);
791
792 OUString sURL;
793 if ( GetProperty( xShapeProps, "URL" ) )
794 mAny >>= sURL;
795 if( !sURL.isEmpty() )
796 {
797 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
799 mpURLTransformer->getTransformedString(sURL),
800 mpURLTransformer->isExternalURL(sURL));
801
802 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
803 }
804 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
805
806 pFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
807
809 pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
810 pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
811
812 // visual chart properties
814
815 // writer chart object
816 pFS->startElement(FSNS(XML_a, XML_graphic));
817 pFS->startElement( FSNS( XML_a, XML_graphicData ),
818 XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart" );
819 OUString sId;
820 const char* sFullPath = nullptr;
821 const char* sRelativePath = nullptr;
822 switch( GetDocumentType() )
823 {
824 case DOCUMENT_DOCX:
825 {
826 sFullPath = "word/charts/chart";
827 sRelativePath = "charts/chart";
828 break;
829 }
830 case DOCUMENT_PPTX:
831 {
832 sFullPath = "ppt/charts/chart";
833 sRelativePath = "../charts/chart";
834 break;
835 }
836 case DOCUMENT_XLSX:
837 {
838 sFullPath = "xl/charts/chart";
839 sRelativePath = "../charts/chart";
840 break;
841 }
842 default:
843 {
844 sFullPath = "charts/chart";
845 sRelativePath = "charts/chart";
846 break;
847 }
848 }
849 OUString sFullStream = OUStringBuffer()
850 .appendAscii(sFullPath)
851 .append(OUString::number(nChartCount) + ".xml")
852 .makeStringAndClear();
853 OUString sRelativeStream = OUStringBuffer()
854 .appendAscii(sRelativePath)
855 .append(OUString::number(nChartCount) + ".xml" )
856 .makeStringAndClear();
858 sFullStream,
859 sRelativeStream,
860 pFS->getOutputStream(),
861 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
862 OUStringToOString(oox::getRelationship(Relationship::CHART), RTL_TEXTENCODING_UTF8).getStr(),
863 &sId );
864
865 XmlFilterBase* pFB = GetFB();
866 pFS->singleElement( FSNS( XML_c, XML_chart ),
867 FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart)),
868 FSNS(XML_xmlns, XML_r), pFB->getNamespaceURL(OOX_NS(officeRel)),
869 FSNS(XML_r, XML_id), sId );
870
871 pFS->endElement( FSNS( XML_a, XML_graphicData ) );
872 pFS->endElement( FSNS( XML_a, XML_graphic ) );
873 pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
874
875 SetFS( pChart );
877 SetFS( pFS );
878 pChart->endDocument();
879}
880
882{
883 if( !xChartDoc.is())
884 return;
885
886 try
887 {
888 Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
889 OSL_ENSURE( xDataProvider.is(), "No DataProvider" );
890 if( xDataProvider.is())
891 {
893 }
894 }
895 catch( const uno::Exception & )
896 {
898 }
899}
900
902{
903 Reference< chart2::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
904 OSL_ASSERT( xChartDoc.is() );
905 if( !xChartDoc.is() )
906 return;
908 // TODO: export chart
910}
911
913{
914 Reference< css::chart::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
915 if( xChartDoc.is())
916 {
917 // determine if data comes from the outside
918 bool bIncludeTable = true;
919
920 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
921 if( xNewDoc.is())
922 {
923 // check if we have own data. If so we must not export the complete
924 // range string, as this is our only indicator for having own or
925 // external data. @todo: fix this in the file format!
926 Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
927 if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
928 {
929 bIncludeTable = false;
930 }
931 }
932 exportChartSpace( xChartDoc, bIncludeTable );
933 }
934 else
935 {
936 OSL_FAIL( "Couldn't export chart due to wrong XModel" );
937 }
938}
939
941 bool bIncludeTable )
942{
943 FSHelperPtr pFS = GetFS();
944 XmlFilterBase* pFB = GetFB();
945 pFS->startElement( FSNS( XML_c, XML_chartSpace ),
946 FSNS( XML_xmlns, XML_c ), pFB->getNamespaceURL(OOX_NS(dmlChart)),
947 FSNS( XML_xmlns, XML_a ), pFB->getNamespaceURL(OOX_NS(dml)),
948 FSNS( XML_xmlns, XML_r ), pFB->getNamespaceURL(OOX_NS(officeRel)));
949 // TODO: get the correct editing language
950 pFS->singleElement(FSNS(XML_c, XML_lang), XML_val, "en-US");
951
952 pFS->singleElement(FSNS(XML_c, XML_roundedCorners), XML_val, "0");
953
954 if( !bIncludeTable )
955 {
956 // TODO:external data
957 }
958 //XML_chart
959 exportChart(xChartDoc);
960
961 // TODO: printSettings
962 // TODO: style
963 // TODO: text properties
964 // TODO: shape properties
965 Reference< XPropertySet > xPropSet = xChartDoc->getArea();
966 if( xPropSet.is() )
967 exportShapeProps( xPropSet );
968
969 //XML_externalData
970 exportExternalData(xChartDoc);
971
972 // export additional shapes in chart
973 exportAdditionalShapes(xChartDoc);
974
975 pFS->endElement( FSNS( XML_c, XML_chartSpace ) );
976}
977
979{
980 // Embedded external data is grab bagged for docx file hence adding export part of
981 // external data for docx files only.
983 return;
984
985 OUString externalDataPath;
986 Reference< beans::XPropertySet > xDocPropSet( xChartDoc->getDiagram(), uno::UNO_QUERY );
987 if( xDocPropSet.is())
988 {
989 try
990 {
991 Any aAny( xDocPropSet->getPropertyValue( "ExternalData" ));
992 aAny >>= externalDataPath;
993 }
994 catch( beans::UnknownPropertyException & )
995 {
996 SAL_WARN("oox", "Required property not found in ChartDocument");
997 }
998 }
999 if(externalDataPath.isEmpty())
1000 return;
1001
1002 // Here adding external data entry to relationship.
1003 OUString relationPath = externalDataPath;
1004 // Converting absolute path to relative path.
1005 if( externalDataPath[ 0 ] != '.' && externalDataPath[ 1 ] != '.')
1006 {
1007 sal_Int32 nSepPos = externalDataPath.indexOf( '/', 0 );
1008 if( nSepPos > 0)
1009 {
1010 relationPath = relationPath.copy( nSepPos, ::std::max< sal_Int32 >( externalDataPath.getLength(), 0 ) - nSepPos );
1011 relationPath = ".." + relationPath;
1012 }
1013 }
1014 FSHelperPtr pFS = GetFS();
1016 if (relationPath.endsWith(".bin"))
1018
1019 OUString sRelId = GetFB()->addRelation(pFS->getOutputStream(),
1020 type,
1021 relationPath);
1022 pFS->singleElementNS(XML_c, XML_externalData, FSNS(XML_r, XML_id), sRelId);
1023}
1024
1026{
1027 Reference< beans::XPropertySet > xDocPropSet(xChartDoc, uno::UNO_QUERY);
1028 if (!xDocPropSet.is())
1029 return;
1030
1031 css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes;
1032 // get a sequence of non-chart shapes
1033 try
1034 {
1035 Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes");
1036 if( (aShapesAny >>= mxAdditionalShapes) && mxAdditionalShapes.is() )
1037 {
1038 OUString sId;
1039 const char* sFullPath = nullptr;
1040 const char* sRelativePath = nullptr;
1041 sal_Int32 nDrawing = getNewDrawingUniqueId();
1042
1043 switch (GetDocumentType())
1044 {
1045 case DOCUMENT_DOCX:
1046 {
1047 sFullPath = "word/drawings/drawing";
1048 sRelativePath = "../drawings/drawing";
1049 break;
1050 }
1051 case DOCUMENT_PPTX:
1052 {
1053 sFullPath = "ppt/drawings/drawing";
1054 sRelativePath = "../drawings/drawing";
1055 break;
1056 }
1057 case DOCUMENT_XLSX:
1058 {
1059 sFullPath = "xl/drawings/drawing";
1060 sRelativePath = "../drawings/drawing";
1061 break;
1062 }
1063 default:
1064 {
1065 sFullPath = "drawings/drawing";
1066 sRelativePath = "drawings/drawing";
1067 break;
1068 }
1069 }
1070 OUString sFullStream = OUStringBuffer()
1071 .appendAscii(sFullPath)
1072 .append(OUString::number(nDrawing) + ".xml")
1073 .makeStringAndClear();
1074 OUString sRelativeStream = OUStringBuffer()
1075 .appendAscii(sRelativePath)
1076 .append(OUString::number(nDrawing) + ".xml")
1077 .makeStringAndClear();
1078
1080 sFullStream,
1081 sRelativeStream,
1083 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml",
1085 &sId);
1086
1087 GetFS()->singleElementNS(XML_c, XML_userShapes, FSNS(XML_r, XML_id), sId);
1088
1089 XmlFilterBase* pFB = GetFB();
1090 pDrawing->startElement(FSNS(XML_c, XML_userShapes),
1091 FSNS(XML_xmlns, XML_cdr), pFB->getNamespaceURL(OOX_NS(dmlChartDr)),
1092 FSNS(XML_xmlns, XML_a), pFB->getNamespaceURL(OOX_NS(dml)),
1093 FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart)),
1094 FSNS(XML_xmlns, XML_r), pFB->getNamespaceURL(OOX_NS(officeRel)));
1095
1096 const sal_Int32 nShapeCount(mxAdditionalShapes->getCount());
1097 for (sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
1098 {
1100 mxAdditionalShapes->getByIndex(nShapeId) >>= xShape;
1101 SAL_WARN_IF(!xShape.is(), "xmloff.chart", "Shape without an XShape?");
1102 if (!xShape.is())
1103 continue;
1104
1105 // TODO: absSizeAnchor: we import both (absSizeAnchor and relSizeAnchor), but there is no essential difference between them.
1106 pDrawing->startElement(FSNS(XML_cdr, XML_relSizeAnchor));
1107 uno::Reference< beans::XPropertySet > xShapeProperties(xShape, uno::UNO_QUERY);
1108 if( xShapeProperties.is() )
1109 {
1110 Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1111 awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1112 WriteFromTo( xShape, aPageSize, pDrawing );
1113
1114 ShapeExport aExport(XML_cdr, pDrawing, nullptr, GetFB(), GetDocumentType(), nullptr, true);
1115 aExport.WriteShape(xShape);
1116 }
1117 pDrawing->endElement(FSNS(XML_cdr, XML_relSizeAnchor));
1118 }
1119 pDrawing->endElement(FSNS(XML_c, XML_userShapes));
1120 pDrawing->endDocument();
1121 }
1122 }
1123 catch (const uno::Exception&)
1124 {
1125 TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found");
1126 }
1127}
1128
1130{
1131 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
1132 mxDiagram.set( xChartDoc->getDiagram() );
1133 if( xNewDoc.is())
1134 mxNewDiagram.set( xNewDoc->getFirstDiagram());
1135
1136 // get Properties of ChartDocument
1137 bool bHasMainTitle = false;
1138 OUString aSubTitle;
1139 bool bHasLegend = false;
1140 Reference< beans::XPropertySet > xDocPropSet( xChartDoc, uno::UNO_QUERY );
1141 if( xDocPropSet.is())
1142 {
1143 try
1144 {
1145 Any aAny( xDocPropSet->getPropertyValue("HasMainTitle"));
1146 aAny >>= bHasMainTitle;
1147 aAny = xDocPropSet->getPropertyValue("HasLegend");
1148 aAny >>= bHasLegend;
1149 }
1150 catch( beans::UnknownPropertyException & )
1151 {
1152 SAL_WARN("oox", "Required property not found in ChartDocument");
1153 }
1154 } // if( xDocPropSet.is())
1155
1156 Reference< beans::XPropertySet > xPropSubTitle( xChartDoc->getSubTitle(), UNO_QUERY );
1157 if( xPropSubTitle.is())
1158 {
1159 try
1160 {
1161 xPropSubTitle->getPropertyValue("String") >>= aSubTitle;
1162 }
1163 catch( beans::UnknownPropertyException & )
1164 {
1165 }
1166 }
1167
1168 // chart element
1169 FSHelperPtr pFS = GetFS();
1170 pFS->startElement(FSNS(XML_c, XML_chart));
1171
1172 // titles
1173 if( bHasMainTitle )
1174 {
1175 exportTitle( xChartDoc->getTitle(), !aSubTitle.isEmpty() ? &aSubTitle : nullptr );
1176 pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0");
1177 }
1178 else if( !aSubTitle.isEmpty() )
1179 {
1180 exportTitle( xChartDoc->getSubTitle(), nullptr );
1181 pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0");
1182 }
1183 else
1184 {
1185 pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "1");
1186 }
1187
1188 InitPlotArea( );
1189 if( mbIs3DChart )
1190 {
1191 exportView3D();
1192
1193 // floor
1195 if( xFloor.is() )
1196 {
1197 pFS->startElement(FSNS(XML_c, XML_floor));
1198 exportShapeProps( xFloor );
1199 pFS->endElement( FSNS( XML_c, XML_floor ) );
1200 }
1201
1202 // LibreOffice doesn't distinguish between sideWall and backWall (both are using the same color).
1203 // It is controlled by the same Wall property.
1205 if( xWall.is() )
1206 {
1207 // sideWall
1208 pFS->startElement(FSNS(XML_c, XML_sideWall));
1209 exportShapeProps( xWall );
1210 pFS->endElement( FSNS( XML_c, XML_sideWall ) );
1211
1212 // backWall
1213 pFS->startElement(FSNS(XML_c, XML_backWall));
1214 exportShapeProps( xWall );
1215 pFS->endElement( FSNS( XML_c, XML_backWall ) );
1216 }
1217
1218 }
1219 // plot area
1220 exportPlotArea( xChartDoc );
1221 // legend
1222 if( bHasLegend )
1223 exportLegend( xChartDoc );
1224
1225 uno::Reference<beans::XPropertySet> xDiagramPropSet(xChartDoc->getDiagram(), uno::UNO_QUERY);
1226 uno::Any aPlotVisOnly = xDiagramPropSet->getPropertyValue("IncludeHiddenCells");
1227 bool bIncludeHiddenCells = false;
1228 aPlotVisOnly >>= bIncludeHiddenCells;
1229 pFS->singleElement(FSNS(XML_c, XML_plotVisOnly), XML_val, ToPsz10(!bIncludeHiddenCells));
1230
1232
1233 pFS->endElement( FSNS( XML_c, XML_chart ) );
1234}
1235
1236void ChartExport::exportMissingValueTreatment(const uno::Reference<beans::XPropertySet>& xPropSet)
1237{
1238 if (!xPropSet.is())
1239 return;
1240
1241 sal_Int32 nVal = 0;
1242 uno::Any aAny = xPropSet->getPropertyValue("MissingValueTreatment");
1243 if (!(aAny >>= nVal))
1244 return;
1245
1246 const char* pVal = nullptr;
1247 switch (nVal)
1248 {
1249 case cssc::MissingValueTreatment::LEAVE_GAP:
1250 pVal = "gap";
1251 break;
1252 case cssc::MissingValueTreatment::USE_ZERO:
1253 pVal = "zero";
1254 break;
1255 case cssc::MissingValueTreatment::CONTINUE:
1256 pVal = "span";
1257 break;
1258 default:
1259 SAL_WARN("oox", "unknown MissingValueTreatment value");
1260 break;
1261 }
1262
1263 FSHelperPtr pFS = GetFS();
1264 pFS->singleElement(FSNS(XML_c, XML_dispBlanksAs), XML_val, pVal);
1265}
1266
1268{
1269 FSHelperPtr pFS = GetFS();
1270 pFS->startElement(FSNS(XML_c, XML_legend));
1271
1272 Reference< beans::XPropertySet > xProp( xChartDoc->getLegend(), uno::UNO_QUERY );
1273 if( xProp.is() )
1274 {
1275 // position
1276 css::chart::ChartLegendPosition aLegendPos = css::chart::ChartLegendPosition_NONE;
1277 try
1278 {
1279 Any aAny( xProp->getPropertyValue( "Alignment" ));
1280 aAny >>= aLegendPos;
1281 }
1282 catch( beans::UnknownPropertyException & )
1283 {
1284 SAL_WARN("oox", "Property Align not found in ChartLegend");
1285 }
1286
1287 const char* strPos = nullptr;
1288 switch( aLegendPos )
1289 {
1290 case css::chart::ChartLegendPosition_LEFT:
1291 strPos = "l";
1292 break;
1293 case css::chart::ChartLegendPosition_RIGHT:
1294 strPos = "r";
1295 break;
1296 case css::chart::ChartLegendPosition_TOP:
1297 strPos = "t";
1298 break;
1299 case css::chart::ChartLegendPosition_BOTTOM:
1300 strPos = "b";
1301 break;
1302 case css::chart::ChartLegendPosition_NONE:
1303 case css::chart::ChartLegendPosition::ChartLegendPosition_MAKE_FIXED_SIZE:
1304 // nothing
1305 break;
1306 }
1307
1308 if( strPos != nullptr )
1309 {
1310 pFS->singleElement(FSNS(XML_c, XML_legendPos), XML_val, strPos);
1311 }
1312
1313 // legendEntry
1314 Reference<chart2::XCoordinateSystemContainer> xCooSysContainer(mxNewDiagram, UNO_QUERY_THROW);
1315 const Sequence<Reference<chart2::XCoordinateSystem>> xCooSysSequence(xCooSysContainer->getCoordinateSystems());
1316
1317 sal_Int32 nIndex = 0;
1318 bool bShowLegendEntry;
1319 for (const auto& rCooSys : xCooSysSequence)
1320 {
1321 PropertySet aCooSysProp(rCooSys);
1322 bool bSwapXAndY = aCooSysProp.getBoolProperty(PROP_SwapXAndYAxis);
1323
1324 Reference<chart2::XChartTypeContainer> xChartTypeContainer(rCooSys, UNO_QUERY_THROW);
1325 const Sequence<Reference<chart2::XChartType>> xChartTypeSequence(xChartTypeContainer->getChartTypes());
1326 if (!xChartTypeSequence.hasElements())
1327 continue;
1328
1329 for (const auto& rCT : xChartTypeSequence)
1330 {
1331 Reference<chart2::XDataSeriesContainer> xDSCont(rCT, UNO_QUERY);
1332 if (!xDSCont.is())
1333 continue;
1334
1335 OUString aChartType(rCT->getChartType());
1336 bool bIsPie = lcl_getChartType(aChartType) == chart::TYPEID_PIE;
1337 if (bIsPie)
1338 {
1339 PropertySet xChartTypeProp(rCT);
1340 bIsPie = !xChartTypeProp.getBoolProperty(PROP_UseRings);
1341 }
1342 const Sequence<Reference<chart2::XDataSeries>> aDataSeriesSeq = xDSCont->getDataSeries();
1343 if (bSwapXAndY)
1344 nIndex += aDataSeriesSeq.getLength() - 1;
1345 for (const auto& rDataSeries : aDataSeriesSeq)
1346 {
1347 PropertySet aSeriesProp(rDataSeries);
1348 bool bVaryColorsByPoint = aSeriesProp.getBoolProperty(PROP_VaryColorsByPoint);
1349 if (bVaryColorsByPoint || bIsPie)
1350 {
1351 Sequence<sal_Int32> deletedLegendEntriesSeq;
1352 aSeriesProp.getProperty(deletedLegendEntriesSeq, PROP_DeletedLegendEntries);
1353 for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq))
1354 {
1355 pFS->startElement(FSNS(XML_c, XML_legendEntry));
1356 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val,
1357 OString::number(nIndex + deletedLegendEntry));
1358 pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, "1");
1359 pFS->endElement(FSNS(XML_c, XML_legendEntry));
1360 }
1361 Reference<chart2::data::XDataSource> xDSrc(rDataSeries, UNO_QUERY);
1362 if (!xDSrc.is())
1363 continue;
1364
1365 const Sequence<Reference<chart2::data::XLabeledDataSequence>> aDataSeqs = xDSrc->getDataSequences();
1366 for (const auto& rDataSeq : aDataSeqs)
1367 {
1368 Reference<chart2::data::XDataSequence> xValues = rDataSeq->getValues();
1369 if (!xValues.is())
1370 continue;
1371
1372 sal_Int32 nDataSeqSize = xValues->getData().getLength();
1373 nIndex += nDataSeqSize;
1374 }
1375 }
1376 else
1377 {
1378 bShowLegendEntry = aSeriesProp.getBoolProperty(PROP_ShowLegendEntry);
1379 if (!bShowLegendEntry)
1380 {
1381 pFS->startElement(FSNS(XML_c, XML_legendEntry));
1382 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val,
1383 OString::number(nIndex));
1384 pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, "1");
1385 pFS->endElement(FSNS(XML_c, XML_legendEntry));
1386 }
1387 bSwapXAndY ? nIndex-- : nIndex++;
1388 }
1389 }
1390 if (bSwapXAndY)
1391 nIndex += aDataSeriesSeq.getLength() + 1;
1392 }
1393 }
1394
1395 uno::Any aRelativePos = xProp->getPropertyValue("RelativePosition");
1396 if (aRelativePos.hasValue())
1397 {
1398 pFS->startElement(FSNS(XML_c, XML_layout));
1399 pFS->startElement(FSNS(XML_c, XML_manualLayout));
1400
1401 pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1402 pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1403 chart2::RelativePosition aPos = aRelativePos.get<chart2::RelativePosition>();
1404
1405 const double x = aPos.Primary;
1406 const double y = aPos.Secondary;
1407
1408 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1409 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1410
1411 uno::Any aRelativeSize = xProp->getPropertyValue("RelativeSize");
1412 if (aRelativeSize.hasValue())
1413 {
1414 chart2::RelativeSize aSize = aRelativeSize.get<chart2::RelativeSize>();
1415
1416 const double w = aSize.Primary;
1417 const double h = aSize.Secondary;
1418
1419 pFS->singleElement(FSNS(XML_c, XML_w), XML_val, OString::number(w));
1420
1421 pFS->singleElement(FSNS(XML_c, XML_h), XML_val, OString::number(h));
1422 }
1423
1424 SAL_WARN_IF(aPos.Anchor != css::drawing::Alignment_TOP_LEFT, "oox", "unsupported anchor position");
1425
1426 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1427 pFS->endElement(FSNS(XML_c, XML_layout));
1428 }
1429
1430 if (strPos != nullptr)
1431 {
1432 uno::Any aOverlay = xProp->getPropertyValue("Overlay");
1433 if(aOverlay.get<bool>())
1434 pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "1");
1435 else
1436 pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "0");
1437 }
1438
1439 // shape properties
1440 exportShapeProps( xProp );
1441
1442 // draw-chart:txPr text properties
1443 exportTextProps( xProp );
1444 }
1445
1446 pFS->endElement( FSNS( XML_c, XML_legend ) );
1447}
1448
1449void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString* pSubText)
1450{
1451 OUString sText;
1452 Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1453 if( xPropSet.is())
1454 {
1455 xPropSet->getPropertyValue("String") >>= sText;
1456 }
1457
1458 // tdf#101322: add subtitle to title
1459 if( pSubText )
1460 sText = sText.isEmpty() ? *pSubText : sText + "\n" + *pSubText;
1461
1462 if( sText.isEmpty() )
1463 return;
1464
1465 FSHelperPtr pFS = GetFS();
1466 pFS->startElement(FSNS(XML_c, XML_title));
1467
1468 pFS->startElement(FSNS(XML_c, XML_tx));
1469 pFS->startElement(FSNS(XML_c, XML_rich));
1470
1471 // TODO: bodyPr
1472 const char* sWritingMode = nullptr;
1473 bool bVertical = false;
1474 xPropSet->getPropertyValue("StackedText") >>= bVertical;
1475 if( bVertical )
1476 sWritingMode = "wordArtVert";
1477
1478 sal_Int32 nRotation = 0;
1479 xPropSet->getPropertyValue("TextRotation") >>= nRotation;
1480
1481 pFS->singleElement( FSNS( XML_a, XML_bodyPr ),
1482 XML_vert, sWritingMode,
1483 XML_rot, oox::drawingml::calcRotationValue(nRotation) );
1484 // TODO: lstStyle
1485 pFS->singleElement(FSNS(XML_a, XML_lstStyle));
1486 // FIXME: handle multiple paragraphs to parse aText
1487 pFS->startElement(FSNS(XML_a, XML_p));
1488
1489 pFS->startElement(FSNS(XML_a, XML_pPr));
1490
1491 bool bDummy = false;
1492 sal_Int32 nDummy;
1493 WriteRunProperties(xPropSet, false, XML_defRPr, true, bDummy, nDummy );
1494
1495 pFS->endElement( FSNS( XML_a, XML_pPr ) );
1496
1497 pFS->startElement(FSNS(XML_a, XML_r));
1498 bDummy = false;
1499 WriteRunProperties( xPropSet, false, XML_rPr, true, bDummy, nDummy );
1500 pFS->startElement(FSNS(XML_a, XML_t));
1501 pFS->writeEscaped( sText );
1502 pFS->endElement( FSNS( XML_a, XML_t ) );
1503 pFS->endElement( FSNS( XML_a, XML_r ) );
1504
1505 pFS->endElement( FSNS( XML_a, XML_p ) );
1506
1507 pFS->endElement( FSNS( XML_c, XML_rich ) );
1508 pFS->endElement( FSNS( XML_c, XML_tx ) );
1509
1510 uno::Any aManualLayout = xPropSet->getPropertyValue("RelativePosition");
1511 if (aManualLayout.hasValue())
1512 {
1513 pFS->startElement(FSNS(XML_c, XML_layout));
1514 pFS->startElement(FSNS(XML_c, XML_manualLayout));
1515 pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1516 pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1517
1518 Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1519 awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1520
1521 awt::Size aSize = xShape->getSize();
1522 awt::Point aPos2 = xShape->getPosition();
1523 // rotated shapes need special handling...
1524 double fSin = fabs(sin(basegfx::deg2rad<100>(nRotation)));
1525 // remove part of height from X direction, if title is rotated down
1526 if( nRotation*0.01 > 180.0 )
1527 aPos2.X -= static_cast<sal_Int32>(fSin * aSize.Height + 0.5);
1528 // remove part of width from Y direction, if title is rotated up
1529 else if( nRotation*0.01 > 0.0 )
1530 aPos2.Y -= static_cast<sal_Int32>(fSin * aSize.Width + 0.5);
1531
1532 double x = static_cast<double>(aPos2.X) / static_cast<double>(aPageSize.Width);
1533 double y = static_cast<double>(aPos2.Y) / static_cast<double>(aPageSize.Height);
1534 /*
1535 pFS->singleElement(FSNS(XML_c, XML_wMode), XML_val, "edge");
1536 pFS->singleElement(FSNS(XML_c, XML_hMode), XML_val, "edge");
1537 */
1538 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1539 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1540 /*
1541 pFS->singleElement(FSNS(XML_c, XML_w), XML_val, "");
1542 pFS->singleElement(FSNS(XML_c, XML_h), XML_val, "");
1543 */
1544 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1545 pFS->endElement(FSNS(XML_c, XML_layout));
1546 }
1547
1548 pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "0");
1549
1550 // shape properties
1551 if( xPropSet.is() )
1552 {
1553 exportShapeProps( xPropSet );
1554 }
1555
1556 pFS->endElement( FSNS( XML_c, XML_title ) );
1557}
1558
1559namespace {
1560
1561 std::vector<Sequence<Reference<chart2::XDataSeries> > > splitDataSeriesByAxis(const Reference< chart2::XChartType >& xChartType)
1562 {
1563 std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitSeries;
1564 std::map<sal_Int32, size_t> aMapAxisToIndex;
1565
1566 Reference< chart2::XDataSeriesContainer > xDSCnt(xChartType, uno::UNO_QUERY);
1567 if (xDSCnt.is())
1568 {
1569 sal_Int32 nAxisIndexOfFirstSeries = -1;
1570 const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq(xDSCnt->getDataSeries());
1571 for (const uno::Reference<chart2::XDataSeries>& xSeries : aSeriesSeq)
1572 {
1573 Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
1574 if (!xPropSet.is())
1575 continue;
1576
1577 sal_Int32 nAxisIndex = -1;
1578 uno::Any aAny = xPropSet->getPropertyValue("AttachedAxisIndex");
1579 aAny >>= nAxisIndex;
1580 size_t nVectorPos = 0;
1581 if (nAxisIndexOfFirstSeries == -1)
1582 {
1583 nAxisIndexOfFirstSeries = nAxisIndex;
1584 }
1585
1586 auto it = aMapAxisToIndex.find(nAxisIndex);
1587 if (it == aMapAxisToIndex.end())
1588 {
1589 aSplitSeries.emplace_back();
1590 nVectorPos = aSplitSeries.size() - 1;
1591 aMapAxisToIndex.insert(std::pair<sal_Int32, size_t>(nAxisIndex, nVectorPos));
1592 }
1593 else
1594 {
1595 nVectorPos = it->second;
1596 }
1597
1598 uno::Sequence<Reference<chart2::XDataSeries> >& rAxisSeriesSeq = aSplitSeries[nVectorPos];
1599 sal_Int32 nLength = rAxisSeriesSeq.getLength();
1600 rAxisSeriesSeq.realloc(nLength + 1);
1601 rAxisSeriesSeq.getArray()[nLength] = xSeries;
1602 }
1603 // if the first series attached to secondary axis, then export those series first, which are attached to primary axis
1604 // also the MS Office export every time in this order
1605 if (aSplitSeries.size() > 1 && nAxisIndexOfFirstSeries == 1)
1606 {
1607 std::swap(aSplitSeries[0], aSplitSeries[1]);
1608 }
1609 }
1610
1611 return aSplitSeries;
1612 }
1613
1614}
1615
1617{
1619 if( ! xBCooSysCnt.is())
1620 return;
1621
1622 // plot-area element
1623
1624 FSHelperPtr pFS = GetFS();
1625 pFS->startElement(FSNS(XML_c, XML_plotArea));
1626
1627 Reference<beans::XPropertySet> xWall(mxNewDiagram, uno::UNO_QUERY);
1628 if( xWall.is() )
1629 {
1630 uno::Any aAny = xWall->getPropertyValue("RelativePosition");
1631 if (aAny.hasValue())
1632 {
1633 chart2::RelativePosition aPos = aAny.get<chart2::RelativePosition>();
1634 aAny = xWall->getPropertyValue("RelativeSize");
1635 chart2::RelativeSize aSize = aAny.get<chart2::RelativeSize>();
1636 uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( xChartDoc->getDiagram(), uno::UNO_QUERY );
1637 exportManualLayout(aPos, aSize, xDiagramPositioning->isExcludingDiagramPositioning() );
1638 }
1639 }
1640
1641 // chart type
1643 aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
1644
1645 // tdf#123647 Save empty chart as empty bar chart.
1646 if (!aCooSysSeq.hasElements())
1647 {
1648 pFS->startElement(FSNS(XML_c, XML_barChart));
1649 pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, "col");
1650 pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, "clustered");
1651 pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
1652 exportAxesId(true);
1653 pFS->endElement(FSNS(XML_c, XML_barChart));
1654 }
1655
1656 for( const auto& rCS : aCooSysSeq )
1657 {
1658 Reference< chart2::XChartTypeContainer > xCTCnt( rCS, uno::UNO_QUERY );
1659 if( ! xCTCnt.is())
1660 continue;
1661 mnSeriesCount=0;
1662 const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
1663 for( const auto& rCT : aCTSeq )
1664 {
1665 Reference< chart2::XDataSeriesContainer > xDSCnt( rCT, uno::UNO_QUERY );
1666 if( ! xDSCnt.is())
1667 return;
1668 Reference< chart2::XChartType > xChartType( rCT, uno::UNO_QUERY );
1669 if( ! xChartType.is())
1670 continue;
1671 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
1672 OUString aChartType( xChartType->getChartType());
1673 sal_Int32 eChartType = lcl_getChartType( aChartType );
1674 switch( eChartType )
1675 {
1676 case chart::TYPEID_BAR:
1677 {
1678 exportBarChart( xChartType );
1679 break;
1680 }
1681 case chart::TYPEID_AREA:
1682 {
1683 exportAreaChart( xChartType );
1684 break;
1685 }
1686 case chart::TYPEID_LINE:
1687 {
1688 exportLineChart( xChartType );
1689 break;
1690 }
1692 {
1693 exportBubbleChart( xChartType );
1694 break;
1695 }
1697 {
1698 break;
1699 }
1701 case chart::TYPEID_PIE:
1702 {
1703 exportPieChart( xChartType );
1704 break;
1705 }
1708 {
1709 exportRadarChart( xChartType );
1710 break;
1711 }
1713 {
1714 exportScatterChart( xChartType );
1715 break;
1716 }
1718 {
1719 exportStockChart( xChartType );
1720 break;
1721 }
1723 {
1724 exportSurfaceChart( xChartType );
1725 break;
1726 }
1727 default:
1728 {
1729 SAL_WARN("oox", "ChartExport::exportPlotArea -- not support chart type");
1730 break;
1731 }
1732 }
1733
1734 }
1735 }
1736 //Axis Data
1737 exportAxes( );
1738
1739 // Data Table
1741
1742 // shape properties
1743 /*
1744 * Export the Plot area Shape Properties
1745 * eg: Fill and Outline
1746 */
1747 Reference< css::chart::X3DDisplay > xWallFloorSupplier( mxDiagram, uno::UNO_QUERY );
1748 // tdf#114139 For 2D charts Plot Area equivalent is Chart Wall.
1749 // Unfortunately LibreOffice doesn't have Plot Area equivalent for 3D charts.
1750 // It means that Plot Area couldn't be displayed and changed for 3D chars in LibreOffice.
1751 // We cannot write Wall attributes into Plot Area for 3D charts, because Wall us used as background wall.
1752 if( !mbIs3DChart && xWallFloorSupplier.is() )
1753 {
1754 Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall();
1755 if( xWallPropSet.is() )
1756 {
1757 uno::Any aAny = xWallPropSet->getPropertyValue("LineStyle");
1758 sal_Int32 eChartType = getChartType( );
1759 // Export LineStyle_NONE instead of default linestyle of PlotArea border, because LibreOffice
1760 // make invisible the Wall shape properties, in case of these charts. Or in the future set
1761 // the default LineStyle of these charts to LineStyle_NONE.
1762 bool noSupportWallProp = ( (eChartType == chart::TYPEID_PIE) || (eChartType == chart::TYPEID_RADARLINE) || (eChartType == chart::TYPEID_RADARAREA) );
1763 if ( noSupportWallProp && (aAny != drawing::LineStyle_NONE) )
1764 {
1765 xWallPropSet->setPropertyValue( "LineStyle", uno::Any(drawing::LineStyle_NONE) );
1766 }
1767 exportShapeProps( xWallPropSet );
1768 }
1769 }
1770
1771 pFS->endElement( FSNS( XML_c, XML_plotArea ) );
1772
1773}
1774
1775void ChartExport::exportManualLayout(const css::chart2::RelativePosition& rPos,
1776 const css::chart2::RelativeSize& rSize,
1777 const bool bIsExcludingDiagramPositioning)
1778{
1779 FSHelperPtr pFS = GetFS();
1780 pFS->startElement(FSNS(XML_c, XML_layout));
1781 pFS->startElement(FSNS(XML_c, XML_manualLayout));
1782
1783 // By default layoutTarget is set to "outer" and we shouldn't save it in that case
1784 if ( bIsExcludingDiagramPositioning )
1785 {
1786 pFS->singleElement(FSNS(XML_c, XML_layoutTarget), XML_val, "inner");
1787 }
1788 pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1789 pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1790
1791 double x = rPos.Primary;
1792 double y = rPos.Secondary;
1793 const double w = rSize.Primary;
1794 const double h = rSize.Secondary;
1795 switch (rPos.Anchor)
1796 {
1797 case drawing::Alignment_LEFT:
1798 y -= (h/2);
1799 break;
1800 case drawing::Alignment_TOP_LEFT:
1801 break;
1802 case drawing::Alignment_BOTTOM_LEFT:
1803 y -= h;
1804 break;
1805 case drawing::Alignment_TOP:
1806 x -= (w/2);
1807 break;
1808 case drawing::Alignment_CENTER:
1809 x -= (w/2);
1810 y -= (h/2);
1811 break;
1812 case drawing::Alignment_BOTTOM:
1813 x -= (w/2);
1814 y -= h;
1815 break;
1816 case drawing::Alignment_TOP_RIGHT:
1817 x -= w;
1818 break;
1819 case drawing::Alignment_BOTTOM_RIGHT:
1820 x -= w;
1821 y -= h;
1822 break;
1823 case drawing::Alignment_RIGHT:
1824 y -= (h/2);
1825 x -= w;
1826 break;
1827 default:
1828 SAL_WARN("oox", "unhandled alignment case for manual layout export " << static_cast<sal_uInt16>(rPos.Anchor));
1829 }
1830
1831 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1832
1833 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1834
1835 pFS->singleElement(FSNS(XML_c, XML_w), XML_val, OString::number(w));
1836
1837 pFS->singleElement(FSNS(XML_c, XML_h), XML_val, OString::number(h));
1838
1839 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1840 pFS->endElement(FSNS(XML_c, XML_layout));
1841}
1842
1844{
1845 // Similar to DrawingML::WriteFill, but gradient access via name
1846 if (!GetProperty( xPropSet, "FillStyle" ))
1847 return;
1848 FillStyle aFillStyle(FillStyle_NONE);
1849 mAny >>= aFillStyle;
1850
1851 // map full transparent background to no fill
1852 if (aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ))
1853 {
1854 sal_Int16 nVal = 0;
1855 mAny >>= nVal;
1856 if ( nVal == 100 )
1857 aFillStyle = FillStyle_NONE;
1858 }
1859 OUString sFillTransparenceGradientName;
1860 if (aFillStyle == FillStyle_SOLID
1861 && GetProperty(xPropSet, "FillTransparenceGradientName") && (mAny >>= sFillTransparenceGradientName)
1862 && !sFillTransparenceGradientName.isEmpty())
1863 {
1864 awt::Gradient aTransparenceGradient;
1865 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1866 uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1867 uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1868 rTransparenceValue >>= aTransparenceGradient;
1869 if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff)
1870 aFillStyle = FillStyle_NONE;
1871 }
1872 switch( aFillStyle )
1873 {
1874 case FillStyle_SOLID:
1875 exportSolidFill(xPropSet);
1876 break;
1877 case FillStyle_GRADIENT :
1878 exportGradientFill( xPropSet );
1879 break;
1880 case FillStyle_BITMAP :
1881 exportBitmapFill( xPropSet );
1882 break;
1883 case FillStyle_HATCH:
1884 exportHatch(xPropSet);
1885 break;
1886 case FillStyle_NONE:
1887 mpFS->singleElementNS(XML_a, XML_noFill);
1888 break;
1889 default:
1890 ;
1891 }
1892}
1893
1895{
1896 // Similar to DrawingML::WriteSolidFill, but gradient access via name
1897 // and currently no InteropGrabBag
1898 // get fill color
1899 if (!GetProperty( xPropSet, "FillColor" ))
1900 return;
1901 sal_uInt32 nFillColor = mAny.get<sal_uInt32>();
1902
1903 sal_Int32 nAlpha = MAX_PERCENT;
1904 if (GetProperty( xPropSet, "FillTransparence" ))
1905 {
1906 sal_Int32 nTransparency = 0;
1907 mAny >>= nTransparency;
1908 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
1909 nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
1910 }
1911 // OOXML has no separate transparence gradient but uses transparency in the gradient stops.
1912 // So we merge transparency and color and use gradient fill in such case.
1913 awt::Gradient aTransparenceGradient;
1914 bool bNeedGradientFill(false);
1915 OUString sFillTransparenceGradientName;
1916 if (GetProperty(xPropSet, "FillTransparenceGradientName")
1917 && (mAny >>= sFillTransparenceGradientName)
1918 && !sFillTransparenceGradientName.isEmpty())
1919 {
1920 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1921 uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1922 uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1923 rTransparenceValue >>= aTransparenceGradient;
1924 if (aTransparenceGradient.StartColor != aTransparenceGradient.EndColor)
1925 bNeedGradientFill = true;
1926 else if (aTransparenceGradient.StartColor != 0)
1927 nAlpha = lcl_getAlphaFromTransparenceGradient(aTransparenceGradient, true);
1928 }
1929 // write XML
1930 if (bNeedGradientFill)
1931 {
1932 awt::Gradient aPseudoColorGradient;
1933 aPseudoColorGradient.XOffset = aTransparenceGradient.XOffset;
1934 aPseudoColorGradient.YOffset = aTransparenceGradient.YOffset;
1935 aPseudoColorGradient.StartIntensity = 100;
1936 aPseudoColorGradient.EndIntensity = 100;
1937 aPseudoColorGradient.Angle = aTransparenceGradient.Angle;
1938 aPseudoColorGradient.Border = aTransparenceGradient.Border;
1939 aPseudoColorGradient.Style = aTransparenceGradient.Style;
1940 aPseudoColorGradient.StartColor = nFillColor;
1941 aPseudoColorGradient.EndColor = nFillColor;
1942 aPseudoColorGradient.StepCount = aTransparenceGradient.StepCount;
1943 mpFS->startElementNS(XML_a, XML_gradFill, XML_rotWithShape, "0");
1944 WriteGradientFill(aPseudoColorGradient, aTransparenceGradient);
1945 mpFS->endElementNS(XML_a, XML_gradFill);
1946 }
1947 else
1948 WriteSolidFill(::Color(ColorTransparency, nFillColor & 0xffffff), nAlpha);
1949}
1950
1952{
1953 if (!xPropSet.is())
1954 return;
1955
1956 if (GetProperty(xPropSet, "FillHatchName"))
1957 {
1958 OUString aHatchName;
1959 mAny >>= aHatchName;
1960 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1961 uno::Reference< container::XNameAccess > xHatchTable( xFact->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY );
1962 uno::Any rValue = xHatchTable->getByName(aHatchName);
1963 css::drawing::Hatch aHatch;
1964 rValue >>= aHatch;
1965 WritePattFill(xPropSet, aHatch);
1966 }
1967
1968}
1969
1971{
1972 if( !xPropSet.is() )
1973 return;
1974
1975 OUString sFillBitmapName;
1976 xPropSet->getPropertyValue("FillBitmapName") >>= sFillBitmapName;
1977
1978 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1979 try
1980 {
1981 uno::Reference< container::XNameAccess > xBitmapTable( xFact->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY );
1982 uno::Any rValue = xBitmapTable->getByName( sFillBitmapName );
1983 if (rValue.has<uno::Reference<awt::XBitmap>>())
1984 {
1985 uno::Reference<awt::XBitmap> xBitmap = rValue.get<uno::Reference<awt::XBitmap>>();
1986 uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1987 if (xGraphic.is())
1988 {
1989 WriteXGraphicBlipFill(xPropSet, xGraphic, XML_a, true, true);
1990 }
1991 }
1992 }
1993 catch (const uno::Exception &)
1994 {
1995 TOOLS_WARN_EXCEPTION("oox", "ChartExport::exportBitmapFill");
1996 }
1997}
1998
2000{
2001 if( !xPropSet.is() )
2002 return;
2003
2004 OUString sFillGradientName;
2005 xPropSet->getPropertyValue("FillGradientName") >>= sFillGradientName;
2006
2007 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
2008 try
2009 {
2010 uno::Reference< container::XNameAccess > xGradient( xFact->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY );
2011 uno::Any rGradientValue = xGradient->getByName( sFillGradientName );
2012 awt::Gradient aGradient;
2013 if( rGradientValue >>= aGradient )
2014 {
2015 awt::Gradient aTransparenceGradient;
2016 mpFS->startElementNS(XML_a, XML_gradFill);
2017 OUString sFillTransparenceGradientName;
2018 if( (xPropSet->getPropertyValue("FillTransparenceGradientName") >>= sFillTransparenceGradientName) && !sFillTransparenceGradientName.isEmpty())
2019 {
2020 uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
2021 uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
2022 rTransparenceValue >>= aTransparenceGradient;
2023 WriteGradientFill(aGradient, aTransparenceGradient);
2024 }
2025 else
2026 {
2027 WriteGradientFill(aGradient, aTransparenceGradient, xPropSet);
2028 }
2029 mpFS->endElementNS(XML_a, XML_gradFill);
2030 }
2031 }
2032 catch (const uno::Exception &)
2033 {
2034 TOOLS_INFO_EXCEPTION("oox", "ChartExport::exportGradientFill");
2035 }
2036}
2037
2039{
2040 auto xDataTable = mxNewDiagram->getDataTable();
2041 if (!xDataTable.is())
2042 return;
2043
2044 FSHelperPtr pFS = GetFS();
2045 uno::Reference<beans::XPropertySet> aPropSet(xDataTable, uno::UNO_QUERY);
2046
2047 bool bShowVBorder = false;
2048 bool bShowHBorder = false;
2049 bool bShowOutline = false;
2050 bool bShowKeys = false;
2051
2052 if (GetProperty(aPropSet, "HBorder"))
2053 mAny >>= bShowHBorder;
2054 if (GetProperty(aPropSet, "VBorder"))
2055 mAny >>= bShowVBorder;
2056 if (GetProperty(aPropSet, "Outline"))
2057 mAny >>= bShowOutline;
2058 if (GetProperty(aPropSet, "Keys"))
2059 mAny >>= bShowKeys;
2060
2061 pFS->startElement(FSNS(XML_c, XML_dTable));
2062
2063 if (bShowHBorder)
2064 pFS->singleElement(FSNS(XML_c, XML_showHorzBorder), XML_val, "1" );
2065 if (bShowVBorder)
2066 pFS->singleElement(FSNS(XML_c, XML_showVertBorder), XML_val, "1");
2067 if (bShowOutline)
2068 pFS->singleElement(FSNS(XML_c, XML_showOutline), XML_val, "1");
2069 if (bShowKeys)
2070 pFS->singleElement(FSNS(XML_c, XML_showKeys), XML_val, "1");
2071
2072 exportShapeProps(aPropSet);
2073 exportTextProps(aPropSet);
2074
2075 pFS->endElement(FSNS(XML_c, XML_dTable));
2076}
2077
2079{
2080 FSHelperPtr pFS = GetFS();
2081 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2082 for (const auto& splitDataSeries : aSplitDataSeries)
2083 {
2084 if (!splitDataSeries.hasElements())
2085 continue;
2086
2087 sal_Int32 nTypeId = XML_areaChart;
2088 if (mbIs3DChart)
2089 nTypeId = XML_area3DChart;
2090 pFS->startElement(FSNS(XML_c, nTypeId));
2091
2093 bool bPrimaryAxes = true;
2094 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2095 exportAxesId(bPrimaryAxes);
2096
2097 pFS->endElement(FSNS(XML_c, nTypeId));
2098 }
2099}
2100
2102{
2103 sal_Int32 nTypeId = XML_barChart;
2104 if (mbIs3DChart)
2105 nTypeId = XML_bar3DChart;
2106 FSHelperPtr pFS = GetFS();
2107
2108 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2109 for (const auto& splitDataSeries : aSplitDataSeries)
2110 {
2111 if (!splitDataSeries.hasElements())
2112 continue;
2113
2114 pFS->startElement(FSNS(XML_c, nTypeId));
2115 // bar direction
2116 bool bVertical = false;
2117 Reference< XPropertySet > xPropSet(mxDiagram, uno::UNO_QUERY);
2118 if (GetProperty(xPropSet, "Vertical"))
2119 mAny >>= bVertical;
2120
2121 const char* bardir = bVertical ? "bar" : "col";
2122 pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, bardir);
2123
2124 exportGrouping(true);
2125
2126 exportVaryColors(xChartType);
2127
2128 bool bPrimaryAxes = true;
2129 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2130
2131 Reference< XPropertySet > xTypeProp(xChartType, uno::UNO_QUERY);
2132
2133 if (xTypeProp.is() && GetProperty(xTypeProp, "GapwidthSequence"))
2134 {
2135 uno::Sequence< sal_Int32 > aBarPositionSequence;
2136 mAny >>= aBarPositionSequence;
2137 if (aBarPositionSequence.hasElements())
2138 {
2139 sal_Int32 nGapWidth = aBarPositionSequence[0];
2140 pFS->singleElement(FSNS(XML_c, XML_gapWidth), XML_val, OString::number(nGapWidth));
2141 }
2142 }
2143
2144 if (mbIs3DChart)
2145 {
2146 // Shape
2147 namespace cssc = css::chart;
2148 sal_Int32 nGeom3d = cssc::ChartSolidType::RECTANGULAR_SOLID;
2149 if (xPropSet.is() && GetProperty(xPropSet, "SolidType"))
2150 mAny >>= nGeom3d;
2151 const char* sShapeType = nullptr;
2152 switch (nGeom3d)
2153 {
2154 case cssc::ChartSolidType::RECTANGULAR_SOLID:
2155 sShapeType = "box";
2156 break;
2157 case cssc::ChartSolidType::CONE:
2158 sShapeType = "cone";
2159 break;
2160 case cssc::ChartSolidType::CYLINDER:
2161 sShapeType = "cylinder";
2162 break;
2163 case cssc::ChartSolidType::PYRAMID:
2164 sShapeType = "pyramid";
2165 break;
2166 }
2167 pFS->singleElement(FSNS(XML_c, XML_shape), XML_val, sShapeType);
2168 }
2169
2170 //overlap
2171 if (!mbIs3DChart && xTypeProp.is() && GetProperty(xTypeProp, "OverlapSequence"))
2172 {
2173 uno::Sequence< sal_Int32 > aBarPositionSequence;
2174 mAny >>= aBarPositionSequence;
2175 if (aBarPositionSequence.hasElements())
2176 {
2177 sal_Int32 nOverlap = aBarPositionSequence[0];
2178 // Stacked/Percent Bar/Column chart Overlap-workaround
2179 // Export the Overlap value with 100% for stacked charts,
2180 // because the default overlap value of the Bar/Column chart is 0% and
2181 // LibreOffice do nothing with the overlap value in Stacked charts case,
2182 // unlike the MS Office, which is interpreted differently.
2183 if ((mbStacked || mbPercent) && nOverlap != 100)
2184 {
2185 nOverlap = 100;
2186 pFS->singleElement(FSNS(XML_c, XML_overlap), XML_val, OString::number(nOverlap));
2187 }
2188 else // Normal bar chart
2189 {
2190 pFS->singleElement(FSNS(XML_c, XML_overlap), XML_val, OString::number(nOverlap));
2191 }
2192 }
2193 }
2194
2195 exportAxesId(bPrimaryAxes);
2196
2197 pFS->endElement(FSNS(XML_c, nTypeId));
2198 }
2199}
2200
2202{
2203 FSHelperPtr pFS = GetFS();
2204 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2205 for (const auto& splitDataSeries : aSplitDataSeries)
2206 {
2207 if (!splitDataSeries.hasElements())
2208 continue;
2209
2210 pFS->startElement(FSNS(XML_c, XML_bubbleChart));
2211
2212 exportVaryColors(xChartType);
2213
2214 bool bPrimaryAxes = true;
2215 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2216
2217 exportAxesId(bPrimaryAxes);
2218
2219 pFS->endElement(FSNS(XML_c, XML_bubbleChart));
2220 }
2221}
2222
2224{
2225 FSHelperPtr pFS = GetFS();
2226 pFS->startElement(FSNS(XML_c, XML_doughnutChart));
2227
2228 exportVaryColors(xChartType);
2229
2230 bool bPrimaryAxes = true;
2231 exportAllSeries(xChartType, bPrimaryAxes);
2232 // firstSliceAng
2234 //FIXME: holeSize
2235 pFS->singleElement(FSNS(XML_c, XML_holeSize), XML_val, OString::number(50));
2236
2237 pFS->endElement( FSNS( XML_c, XML_doughnutChart ) );
2238}
2239
2240namespace {
2241
2242void writeDataLabelsRange(const FSHelperPtr& pFS, const XmlFilterBase* pFB, DataLabelsRange& rDLblsRange)
2243{
2244 if (rDLblsRange.empty())
2245 return;
2246
2247 pFS->startElement(FSNS(XML_c, XML_extLst));
2248 pFS->startElement(FSNS(XML_c, XML_ext), XML_uri, "{02D57815-91ED-43cb-92C2-25804820EDAC}", FSNS(XML_xmlns, XML_c15), pFB->getNamespaceURL(OOX_NS(c15)));
2249 pFS->startElement(FSNS(XML_c15, XML_datalabelsRange));
2250
2251 // Write cell range.
2252 pFS->startElement(FSNS(XML_c15, XML_f));
2253 pFS->writeEscaped(rDLblsRange.getRange());
2254 pFS->endElement(FSNS(XML_c15, XML_f));
2255
2256 // Write all labels.
2257 pFS->startElement(FSNS(XML_c15, XML_dlblRangeCache));
2258 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(rDLblsRange.count()));
2259 for (const auto& rLabelKV: rDLblsRange)
2260 {
2261 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(rLabelKV.first));
2262 pFS->startElement(FSNS(XML_c, XML_v));
2263 pFS->writeEscaped(rLabelKV.second);
2264 pFS->endElement(FSNS( XML_c, XML_v ));
2265 pFS->endElement(FSNS(XML_c, XML_pt));
2266 }
2267
2268 pFS->endElement(FSNS(XML_c15, XML_dlblRangeCache));
2269
2270 pFS->endElement(FSNS(XML_c15, XML_datalabelsRange));
2271 pFS->endElement(FSNS(XML_c, XML_ext));
2272 pFS->endElement(FSNS(XML_c, XML_extLst));
2273}
2274
2275}
2276
2278{
2279 FSHelperPtr pFS = GetFS();
2280 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2281 for (const auto& splitDataSeries : aSplitDataSeries)
2282 {
2283 if (!splitDataSeries.hasElements())
2284 continue;
2285
2286 sal_Int32 nTypeId = XML_lineChart;
2287 if( mbIs3DChart )
2288 nTypeId = XML_line3DChart;
2289 pFS->startElement(FSNS(XML_c, nTypeId));
2290
2291 exportGrouping( );
2292
2293 exportVaryColors(xChartType);
2294 // TODO: show marker symbol in series?
2295 bool bPrimaryAxes = true;
2296 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2297
2298 // show marker?
2299 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
2300 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
2301 if( GetProperty( xPropSet, "SymbolType" ) )
2302 mAny >>= nSymbolType;
2303
2304 if( !mbIs3DChart )
2305 {
2307 exportUpDownBars(xChartType);
2308 const char* marker = nSymbolType == css::chart::ChartSymbolType::NONE? "0":"1";
2309 pFS->singleElement(FSNS(XML_c, XML_marker), XML_val, marker);
2310 }
2311
2312 exportAxesId(bPrimaryAxes, true);
2313
2314 pFS->endElement( FSNS( XML_c, nTypeId ) );
2315 }
2316}
2317
2319{
2320 sal_Int32 eChartType = getChartType( );
2321 if(eChartType == chart::TYPEID_DOUGHNUT)
2322 {
2323 exportDoughnutChart( xChartType );
2324 return;
2325 }
2326 FSHelperPtr pFS = GetFS();
2327 sal_Int32 nTypeId = XML_pieChart;
2328 if( mbIs3DChart )
2329 nTypeId = XML_pie3DChart;
2330 pFS->startElement(FSNS(XML_c, nTypeId));
2331
2332 exportVaryColors(xChartType);
2333
2334 bool bPrimaryAxes = true;
2335 exportAllSeries(xChartType, bPrimaryAxes);
2336
2337 if( !mbIs3DChart )
2338 {
2339 // firstSliceAng
2341 }
2342
2343 pFS->endElement( FSNS( XML_c, nTypeId ) );
2344}
2345
2347{
2348 FSHelperPtr pFS = GetFS();
2349 pFS->startElement(FSNS(XML_c, XML_radarChart));
2350
2351 // radarStyle
2352 sal_Int32 eChartType = getChartType( );
2353 const char* radarStyle = nullptr;
2354 if( eChartType == chart::TYPEID_RADARAREA )
2355 radarStyle = "filled";
2356 else
2357 radarStyle = "marker";
2358 pFS->singleElement(FSNS(XML_c, XML_radarStyle), XML_val, radarStyle);
2359
2360 exportVaryColors(xChartType);
2361 bool bPrimaryAxes = true;
2362 exportAllSeries(xChartType, bPrimaryAxes);
2363 exportAxesId(bPrimaryAxes);
2364
2365 pFS->endElement( FSNS( XML_c, XML_radarChart ) );
2366}
2367
2369 const css::uno::Sequence<css::uno::Reference<chart2::XDataSeries>>* pSeries)
2370{
2371 FSHelperPtr pFS = GetFS();
2372 pFS->startElement(FSNS(XML_c, XML_scatterChart));
2373 // TODO:scatterStyle
2374
2375 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
2376 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
2377 if( GetProperty( xPropSet, "SymbolType" ) )
2378 mAny >>= nSymbolType;
2379
2380 const char* scatterStyle = "lineMarker";
2381 if (nSymbolType == css::chart::ChartSymbolType::NONE)
2382 {
2383 scatterStyle = "line";
2384 }
2385
2386 pFS->singleElement(FSNS(XML_c, XML_scatterStyle), XML_val, scatterStyle);
2387
2388 exportVaryColors(xChartType);
2389 // FIXME: should export xVal and yVal
2390 bool bPrimaryAxes = true;
2391 if (pSeries)
2392 exportSeries(xChartType, *pSeries, bPrimaryAxes);
2393 exportAxesId(bPrimaryAxes);
2394
2395 pFS->endElement( FSNS( XML_c, XML_scatterChart ) );
2396}
2397
2399{
2400 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2401 bool bExported = false;
2402 for (const auto& splitDataSeries : aSplitDataSeries)
2403 {
2404 if (!splitDataSeries.hasElements())
2405 continue;
2406
2407 bExported = true;
2408 exportScatterChartSeries(xChartType, &splitDataSeries);
2409 }
2410 if (!bExported)
2411 exportScatterChartSeries(xChartType, nullptr);
2412}
2413
2415{
2416 FSHelperPtr pFS = GetFS();
2417 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2418 for (const auto& splitDataSeries : aSplitDataSeries)
2419 {
2420 if (!splitDataSeries.hasElements())
2421 continue;
2422
2423 pFS->startElement(FSNS(XML_c, XML_stockChart));
2424
2425 bool bPrimaryAxes = true;
2426 exportCandleStickSeries(splitDataSeries, bPrimaryAxes);
2427
2428 // export stock properties
2429 Reference< css::chart::XStatisticDisplay > xStockPropProvider(mxDiagram, uno::UNO_QUERY);
2430 if (xStockPropProvider.is())
2431 {
2433 exportUpDownBars(xChartType);
2434 }
2435
2436 exportAxesId(bPrimaryAxes);
2437
2438 pFS->endElement(FSNS(XML_c, XML_stockChart));
2439 }
2440}
2441
2443{
2444 FSHelperPtr pFS = GetFS();
2445 // export the chart property
2446 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
2447
2448 if (!xChartPropProvider.is())
2449 return;
2450
2451 Reference< beans::XPropertySet > xStockPropSet = xChartPropProvider->getMinMaxLine();
2452 if( !xStockPropSet.is() )
2453 return;
2454
2455 pFS->startElement(FSNS(XML_c, XML_hiLowLines));
2456 exportShapeProps( xStockPropSet );
2457 pFS->endElement( FSNS( XML_c, XML_hiLowLines ) );
2458}
2459
2461{
2462 if(xChartType->getChartType() != "com.sun.star.chart2.CandleStickChartType")
2463 return;
2464
2465 FSHelperPtr pFS = GetFS();
2466 // export the chart property
2467 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
2468 if(!xChartPropProvider.is())
2469 return;
2470
2471 // updownbar
2472 pFS->startElement(FSNS(XML_c, XML_upDownBars));
2473 // TODO: gapWidth
2474 pFS->singleElement(FSNS(XML_c, XML_gapWidth), XML_val, OString::number(150));
2475
2476 Reference< beans::XPropertySet > xChartPropSet = xChartPropProvider->getUpBar();
2477 if( xChartPropSet.is() )
2478 {
2479 pFS->startElement(FSNS(XML_c, XML_upBars));
2480 // For Linechart with UpDownBars, spPr is not getting imported
2481 // so no need to call the exportShapeProps() for LineChart
2482 if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
2483 {
2484 exportShapeProps(xChartPropSet);
2485 }
2486 pFS->endElement( FSNS( XML_c, XML_upBars ) );
2487 }
2488 xChartPropSet = xChartPropProvider->getDownBar();
2489 if( xChartPropSet.is() )
2490 {
2491 pFS->startElement(FSNS(XML_c, XML_downBars));
2492 if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
2493 {
2494 exportShapeProps(xChartPropSet);
2495 }
2496 pFS->endElement( FSNS( XML_c, XML_downBars ) );
2497 }
2498 pFS->endElement( FSNS( XML_c, XML_upDownBars ) );
2499}
2500
2502{
2503 FSHelperPtr pFS = GetFS();
2504 sal_Int32 nTypeId = XML_surfaceChart;
2505 if( mbIs3DChart )
2506 nTypeId = XML_surface3DChart;
2507 pFS->startElement(FSNS(XML_c, nTypeId));
2508 exportVaryColors(xChartType);
2509 bool bPrimaryAxes = true;
2510 exportAllSeries(xChartType, bPrimaryAxes);
2511 exportAxesId(bPrimaryAxes);
2512
2513 pFS->endElement( FSNS( XML_c, nTypeId ) );
2514}
2515
2516void ChartExport::exportAllSeries(const Reference<chart2::XChartType>& xChartType, bool& rPrimaryAxes)
2517{
2518 Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
2519 if( ! xDSCnt.is())
2520 return;
2521
2522 // export dataseries for current chart-type
2523 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
2524 exportSeries(xChartType, aSeriesSeq, rPrimaryAxes);
2525}
2526
2528{
2529 FSHelperPtr pFS = GetFS();
2530 try
2531 {
2532 Reference<chart2::XDataSeries> xDataSeries = getPrimaryDataSeries(xChartType);
2533 Reference<beans::XPropertySet> xDataSeriesProps(xDataSeries, uno::UNO_QUERY_THROW);
2534 Any aAnyVaryColors = xDataSeriesProps->getPropertyValue("VaryColorsByPoint");
2535 bool bVaryColors = false;
2536 aAnyVaryColors >>= bVaryColors;
2537 pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, ToPsz10(bVaryColors));
2538 }
2539 catch (...)
2540 {
2541 pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
2542 }
2543}
2544
2546 const Sequence<Reference<chart2::XDataSeries> >& rSeriesSeq, bool& rPrimaryAxes )
2547{
2548 OUString aLabelRole = xChartType->getRoleOfSequenceForSeriesLabel();
2549 OUString aChartType( xChartType->getChartType());
2550 sal_Int32 eChartType = lcl_getChartType( aChartType );
2551
2552 for( const auto& rSeries : rSeriesSeq )
2553 {
2554 // export series
2555 Reference< chart2::data::XDataSource > xSource( rSeries, uno::UNO_QUERY );
2556 if( xSource.is())
2557 {
2558 Reference< chart2::XDataSeries > xDataSeries( xSource, uno::UNO_QUERY );
2560 xSource->getDataSequences());
2561 // search for main sequence and create a series element
2562 {
2563 sal_Int32 nMainSequenceIndex = -1;
2564 sal_Int32 nSeriesLength = 0;
2567 sal_Int32 nSeqIdx=0;
2568 for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2569 {
2570 Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2571 if( nMainSequenceIndex==-1 )
2572 {
2573 Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2574 OUString aRole;
2575 if( xSeqProp.is())
2576 xSeqProp->getPropertyValue("Role") >>= aRole;
2577 // "main" sequence
2578 if( aRole == aLabelRole )
2579 {
2580 xValuesSeq.set( xTempValueSeq );
2581 xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2582 nMainSequenceIndex = nSeqIdx;
2583 }
2584 }
2585 sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2586 if( nSeriesLength < nSequenceLength )
2587 nSeriesLength = nSequenceLength;
2588 }
2589
2590 // have found the main sequence, then xValuesSeq and
2591 // xLabelSeq contain those. Otherwise both are empty
2592 {
2593 FSHelperPtr pFS = GetFS();
2594
2595 pFS->startElement(FSNS(XML_c, XML_ser));
2596
2597 // TODO: idx and order
2598 pFS->singleElement( FSNS( XML_c, XML_idx ),
2599 XML_val, OString::number(mnSeriesCount) );
2600 pFS->singleElement( FSNS( XML_c, XML_order ),
2601 XML_val, OString::number(mnSeriesCount++) );
2602
2603 // export label
2604 if( xLabelSeq.is() )
2605 exportSeriesText( xLabelSeq );
2606
2607 Reference<XPropertySet> xPropSet(xDataSeries, UNO_QUERY_THROW);
2608 if( GetProperty( xPropSet, "AttachedAxisIndex") )
2609 {
2610 sal_Int32 nLocalAttachedAxis = 0;
2611 mAny >>= nLocalAttachedAxis;
2612 rPrimaryAxes = isPrimaryAxes(nLocalAttachedAxis);
2613 }
2614
2615 // export shape properties
2617 rSeries, getModel() );
2618 if( xOldPropSet.is() )
2619 {
2620 exportShapeProps( xOldPropSet );
2621 }
2622
2623 switch( eChartType )
2624 {
2627 case chart::TYPEID_BAR:
2628 {
2629 pFS->singleElement(FSNS(XML_c, XML_invertIfNegative), XML_val, "0");
2630 }
2631 break;
2632 case chart::TYPEID_LINE:
2633 {
2634 exportMarker(xOldPropSet);
2635 break;
2636 }
2637 case chart::TYPEID_PIE:
2639 {
2640 if( xOldPropSet.is() && GetProperty( xOldPropSet, "SegmentOffset") )
2641 {
2642 sal_Int32 nOffset = 0;
2643 mAny >>= nOffset;
2644 pFS->singleElement( FSNS( XML_c, XML_explosion ),
2645 XML_val, OString::number( nOffset ) );
2646 }
2647 break;
2648 }
2650 {
2651 exportMarker(xOldPropSet);
2652 break;
2653 }
2655 {
2656 exportMarker(xOldPropSet);
2657 break;
2658 }
2659 }
2660
2661 // export data points
2662 exportDataPoints( uno::Reference< beans::XPropertySet >( rSeries, uno::UNO_QUERY ), nSeriesLength, eChartType );
2663
2664 DataLabelsRange aDLblsRange;
2665 // export data labels
2666 exportDataLabels(rSeries, nSeriesLength, eChartType, aDLblsRange);
2667
2668 exportTrendlines( rSeries );
2669
2670 if( eChartType != chart::TYPEID_PIE &&
2671 eChartType != chart::TYPEID_RADARLINE )
2672 {
2673 //export error bars here
2674 Reference< XPropertySet > xSeriesPropSet( xSource, uno::UNO_QUERY );
2675 Reference< XPropertySet > xErrorBarYProps;
2676 xSeriesPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarYProps;
2677 if(xErrorBarYProps.is())
2678 exportErrorBar(xErrorBarYProps, true);
2679 if (eChartType != chart::TYPEID_BAR &&
2680 eChartType != chart::TYPEID_HORBAR)
2681 {
2682 Reference< XPropertySet > xErrorBarXProps;
2683 xSeriesPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarXProps;
2684 if(xErrorBarXProps.is())
2685 exportErrorBar(xErrorBarXProps, false);
2686 }
2687 }
2688
2689 // export categories
2690 if( eChartType != chart::TYPEID_SCATTER && eChartType != chart::TYPEID_BUBBLE && mxCategoriesValues.is() )
2692
2693 if( (eChartType == chart::TYPEID_SCATTER)
2694 || (eChartType == chart::TYPEID_BUBBLE) )
2695 {
2696 // export xVal
2698 if( xSequence.is() )
2699 {
2700 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2701 if( xValues.is() )
2702 exportSeriesValues( xValues, XML_xVal );
2703 }
2704 else if( mxCategoriesValues.is() )
2706 }
2707
2708 if( eChartType == chart::TYPEID_BUBBLE )
2709 {
2710 // export yVal
2712 if( xSequence.is() )
2713 {
2714 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2715 if( xValues.is() )
2716 exportSeriesValues( xValues, XML_yVal );
2717 }
2718 }
2719
2720 // export values
2721 if( xValuesSeq.is() )
2722 {
2723 sal_Int32 nYValueType = XML_val;
2724 if( eChartType == chart::TYPEID_SCATTER )
2725 nYValueType = XML_yVal;
2726 else if( eChartType == chart::TYPEID_BUBBLE )
2727 nYValueType = XML_bubbleSize;
2728 exportSeriesValues( xValuesSeq, nYValueType );
2729 }
2730
2731 if( eChartType == chart::TYPEID_SCATTER
2732 || eChartType == chart::TYPEID_LINE )
2733 exportSmooth();
2734
2735 // tdf103988: "corrupted" files with Bubble chart opening in MSO
2736 if( eChartType == chart::TYPEID_BUBBLE )
2737 pFS->singleElement(FSNS(XML_c, XML_bubble3D), XML_val, "0");
2738
2739 if (!aDLblsRange.empty())
2740 writeDataLabelsRange(pFS, GetFB(), aDLblsRange);
2741
2742 pFS->endElement( FSNS( XML_c, XML_ser ) );
2743 }
2744 }
2745 }
2746 }
2747}
2748
2750 const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
2751 bool& rPrimaryAxes)
2752{
2753 for( const Reference< chart2::XDataSeries >& xSeries : aSeriesSeq )
2754 {
2755 rPrimaryAxes = lcl_isSeriesAttachedToFirstAxis(xSeries);
2756
2757 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
2758 if( xSource.is())
2759 {
2760 // export series in correct order (as we don't store roles)
2761 // with japanese candlesticks: open, low, high, close
2762 // otherwise: low, high, close
2764 xSource->getDataSequences());
2765
2766 const char* sSeries[] = {"values-first","values-max","values-min","values-last",nullptr};
2767
2768 for( sal_Int32 idx = 0; sSeries[idx] != nullptr ; idx++ )
2769 {
2770 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii(sSeries[idx]) ) );
2771 if( xLabeledSeq.is())
2772 {
2773 Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
2774 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
2775 {
2776 FSHelperPtr pFS = GetFS();
2777 pFS->startElement(FSNS(XML_c, XML_ser));
2778
2779 // TODO: idx and order
2780 // idx attribute should start from 1 and not from 0.
2781 pFS->singleElement( FSNS( XML_c, XML_idx ),
2782 XML_val, OString::number(idx+1) );
2783 pFS->singleElement( FSNS( XML_c, XML_order ),
2784 XML_val, OString::number(idx+1) );
2785
2786 // export label
2787 if( xLabelSeq.is() )
2788 exportSeriesText( xLabelSeq );
2789
2790 // TODO:export shape properties
2791
2792 // export categories
2793 if( mxCategoriesValues.is() )
2795
2796 // export values
2797 if( xValueSeq.is() )
2798 exportSeriesValues( xValueSeq );
2799
2800 pFS->endElement( FSNS( XML_c, XML_ser ) );
2801 }
2802 }
2803 }
2804 }
2805 }
2806}
2807
2809{
2810 FSHelperPtr pFS = GetFS();
2811 pFS->startElement(FSNS(XML_c, XML_tx));
2812
2813 OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
2814 aCellRange = parseFormula( aCellRange );
2815 pFS->startElement(FSNS(XML_c, XML_strRef));
2816
2817 pFS->startElement(FSNS(XML_c, XML_f));
2818 pFS->writeEscaped( aCellRange );
2819 pFS->endElement( FSNS( XML_c, XML_f ) );
2820
2821 OUString aLabelString = lcl_flattenStringSequence(lcl_getLabelSequence(xValueSeq));
2822 pFS->startElement(FSNS(XML_c, XML_strCache));
2823 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, "1");
2824 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, "0");
2825 pFS->startElement(FSNS(XML_c, XML_v));
2826 pFS->writeEscaped( aLabelString );
2827 pFS->endElement( FSNS( XML_c, XML_v ) );
2828 pFS->endElement( FSNS( XML_c, XML_pt ) );
2829 pFS->endElement( FSNS( XML_c, XML_strCache ) );
2830 pFS->endElement( FSNS( XML_c, XML_strRef ) );
2831 pFS->endElement( FSNS( XML_c, XML_tx ) );
2832}
2833
2835{
2836 FSHelperPtr pFS = GetFS();
2837 pFS->startElement(FSNS(XML_c, nValueType));
2838
2839 OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2840 const Sequence< Sequence< OUString >> aFinalSplitSource = (nValueType == XML_cat) ? getSplitCategoriesList(aCellRange) : Sequence< Sequence< OUString>>(0);
2841 aCellRange = parseFormula( aCellRange );
2842
2843 if(aFinalSplitSource.getLength() > 1)
2844 {
2845 // export multi level category axis labels
2846 pFS->startElement(FSNS(XML_c, XML_multiLvlStrRef));
2847
2848 pFS->startElement(FSNS(XML_c, XML_f));
2849 pFS->writeEscaped(aCellRange);
2850 pFS->endElement(FSNS(XML_c, XML_f));
2851
2852 pFS->startElement(FSNS(XML_c, XML_multiLvlStrCache));
2853 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(aFinalSplitSource[0].getLength()));
2854 for(const auto& rSeq : aFinalSplitSource)
2855 {
2856 pFS->startElement(FSNS(XML_c, XML_lvl));
2857 for(sal_Int32 j = 0; j < rSeq.getLength(); j++)
2858 {
2859 if(!rSeq[j].isEmpty())
2860 {
2861 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(j));
2862 pFS->startElement(FSNS(XML_c, XML_v));
2863 pFS->writeEscaped(rSeq[j]);
2864 pFS->endElement(FSNS(XML_c, XML_v));
2865 pFS->endElement(FSNS(XML_c, XML_pt));
2866 }
2867 }
2868 pFS->endElement(FSNS(XML_c, XML_lvl));
2869 }
2870
2871 pFS->endElement(FSNS(XML_c, XML_multiLvlStrCache));
2872 pFS->endElement(FSNS(XML_c, XML_multiLvlStrRef));
2873 }
2874 else
2875 {
2876 // export single category axis labels
2877 bool bWriteDateCategories = mbHasDateCategories && (nValueType == XML_cat);
2878 OUString aNumberFormatString;
2879 if (bWriteDateCategories)
2880 {
2881 Reference< css::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
2882 if( xAxisXSupp.is())
2883 {
2884 Reference< XPropertySet > xAxisProp = xAxisXSupp->getXAxis();
2885 if (GetProperty(xAxisProp, "NumberFormat"))
2886 {
2887 sal_Int32 nKey = 0;
2888 mAny >>= nKey;
2889 aNumberFormatString = getNumberFormatCode(nKey);
2890 }
2891 }
2892 if (aNumberFormatString.isEmpty())
2893 bWriteDateCategories = false;
2894 }
2895
2896 pFS->startElement(FSNS(XML_c, bWriteDateCategories ? XML_numRef : XML_strRef));
2897
2898 pFS->startElement(FSNS(XML_c, XML_f));
2899 pFS->writeEscaped(aCellRange);
2900 pFS->endElement(FSNS(XML_c, XML_f));
2901
2902 ::std::vector< OUString > aCategories;
2903 lcl_fillCategoriesIntoStringVector(xValueSeq, aCategories);
2904 sal_Int32 ptCount = aCategories.size();
2905 pFS->startElement(FSNS(XML_c, bWriteDateCategories ? XML_numCache : XML_strCache));
2906 if (bWriteDateCategories)
2907 {
2908 pFS->startElement(FSNS(XML_c, XML_formatCode));
2909 pFS->writeEscaped(aNumberFormatString);
2910 pFS->endElement(FSNS(XML_c, XML_formatCode));
2911 }
2912
2913 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(ptCount));
2914 for (sal_Int32 i = 0; i < ptCount; i++)
2915 {
2916 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(i));
2917 pFS->startElement(FSNS(XML_c, XML_v));
2918 pFS->writeEscaped(aCategories[i]);
2919 pFS->endElement(FSNS(XML_c, XML_v));
2920 pFS->endElement(FSNS(XML_c, XML_pt));
2921 }
2922
2923 pFS->endElement(FSNS(XML_c, bWriteDateCategories ? XML_numCache : XML_strCache));
2924 pFS->endElement(FSNS(XML_c, bWriteDateCategories ? XML_numRef : XML_strRef));
2925 }
2926
2927 pFS->endElement( FSNS( XML_c, nValueType ) );
2928}
2929
2931{
2932 FSHelperPtr pFS = GetFS();
2933 pFS->startElement(FSNS(XML_c, nValueType));
2934
2935 OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2936 aCellRange = parseFormula( aCellRange );
2937 // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2938 pFS->startElement(FSNS(XML_c, XML_numRef));
2939
2940 pFS->startElement(FSNS(XML_c, XML_f));
2941 pFS->writeEscaped( aCellRange );
2942 pFS->endElement( FSNS( XML_c, XML_f ) );
2943
2944 ::std::vector< double > aValues = lcl_getAllValuesFromSequence( xValueSeq );
2945 sal_Int32 ptCount = aValues.size();
2946 pFS->startElement(FSNS(XML_c, XML_numCache));
2947 pFS->startElement(FSNS(XML_c, XML_formatCode));
2948 // TODO: what format code?
2949 pFS->writeEscaped( "General" );
2950 pFS->endElement( FSNS( XML_c, XML_formatCode ) );
2951 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(ptCount));
2952
2953 for( sal_Int32 i = 0; i < ptCount; i++ )
2954 {
2955 if (!std::isnan(aValues[i]))
2956 {
2957 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(i));
2958 pFS->startElement(FSNS(XML_c, XML_v));
2959 pFS->write(aValues[i]);
2960 pFS->endElement(FSNS(XML_c, XML_v));
2961 pFS->endElement(FSNS(XML_c, XML_pt));
2962 }
2963 }
2964
2965 pFS->endElement( FSNS( XML_c, XML_numCache ) );
2966 pFS->endElement( FSNS( XML_c, XML_numRef ) );
2967 pFS->endElement( FSNS( XML_c, nValueType ) );
2968}
2969
2971{
2972 FSHelperPtr pFS = GetFS();
2973 pFS->startElement(FSNS(XML_c, XML_spPr));
2974
2975 exportFill( xPropSet );
2976 WriteOutline( xPropSet, getModel() );
2977
2978 pFS->endElement( FSNS( XML_c, XML_spPr ) );
2979}
2980
2982{
2983 FSHelperPtr pFS = GetFS();
2984 pFS->startElement(FSNS(XML_c, XML_txPr));
2985
2986 sal_Int32 nRotation = 0;
2987 const char* textWordWrap = nullptr;
2988
2989 if (auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xPropSet, uno::UNO_QUERY))
2990 {
2991 double fMultiplier = 0.0;
2992 // We have at least two possible units of returned value: degrees (e.g., for data labels),
2993 // and 100ths of degree (e.g., for axes labels). The latter is returned as an Any wrapping
2994 // a sal_Int32 value (see WrappedTextRotationProperty::convertInnerToOuterValue), while
2995 // the former is double. So we could test the contained type to decide which multiplier to
2996 // use. But testing the service info should be more robust.
2997 if (xServiceInfo->supportsService("com.sun.star.chart.ChartAxis"))
2998 fMultiplier = -600.0;
2999 else if (xServiceInfo->supportsService("com.sun.star.chart2.DataSeries") || xServiceInfo->supportsService("com.sun.star.chart2.DataPointProperties"))
3000 {
3001 fMultiplier = -60000.0;
3002 bool bTextWordWrap = false;
3003 if ((xPropSet->getPropertyValue("TextWordWrap") >>= bTextWordWrap) && bTextWordWrap)
3004 textWordWrap = "square";
3005 else
3006 textWordWrap = "none";
3007 }
3008
3009 if (fMultiplier)
3010 {
3011 double fTextRotation = 0.0;
3012 uno::Any aAny = xPropSet->getPropertyValue("TextRotation");
3013 if (aAny.hasValue() && (aAny >>= fTextRotation))
3014 {
3015 fTextRotation *= fMultiplier;
3016 // The MS Office UI allows values only in range of [-90,90].
3017 if (fTextRotation < -5400000.0 && fTextRotation > -16200000.0)
3018 {
3019 // Reflect the angle if the value is between 90° and 270°
3020 fTextRotation += 10800000.0;
3021 }
3022 else if (fTextRotation <= -16200000.0)
3023 {
3024 fTextRotation += 21600000.0;
3025 }
3026 nRotation = std::round(fTextRotation);
3027 }
3028 }
3029 }
3030
3031 if (nRotation)
3032 pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_rot, OString::number(nRotation), XML_wrap, textWordWrap);
3033 else
3034 pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_wrap, textWordWrap);
3035
3036 pFS->singleElement(FSNS(XML_a, XML_lstStyle));
3037
3038 pFS->startElement(FSNS(XML_a, XML_p));
3039 pFS->startElement(FSNS(XML_a, XML_pPr));
3040
3041 WriteRunProperties(xPropSet, false, XML_defRPr, true, o3tl::temporary(false),
3042 o3tl::temporary(sal_Int32()));
3043
3044 pFS->endElement(FSNS(XML_a, XML_pPr));
3045 pFS->endElement(FSNS(XML_a, XML_p));
3046 pFS->endElement(FSNS(XML_c, XML_txPr));
3047}
3048
3050{
3051 Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
3052
3053 // Check for supported services and then the properties provided by this service.
3054 Reference<lang::XServiceInfo> xServiceInfo (mxDiagram, uno::UNO_QUERY);
3055 if (xServiceInfo.is())
3056 {
3057 if (xServiceInfo->supportsService("com.sun.star.chart.ChartAxisZSupplier"))
3058 {
3059 xDiagramProperties->getPropertyValue("HasZAxis") >>= mbHasZAxis;
3060 }
3061 }
3062
3063 xDiagramProperties->getPropertyValue("Dim3D") >>= mbIs3DChart;
3064
3066 {
3068 if( xCategories.is() )
3069 {
3070 mxCategoriesValues.set( xCategories->getValues() );
3071 }
3072 }
3073}
3074
3076{
3077 sal_Int32 nSize = maAxes.size();
3078 // let's export the axis types in the right order
3079 for ( sal_Int32 nSortIdx = AXIS_PRIMARY_X; nSortIdx <= AXIS_SECONDARY_Y; nSortIdx++ )
3080 {
3081 for ( sal_Int32 nIdx = 0; nIdx < nSize; nIdx++ )
3082 {
3083 if (nSortIdx == maAxes[nIdx].nAxisType)
3084 exportAxis( maAxes[nIdx] );
3085 }
3086 }
3087}
3088
3089namespace {
3090
3091sal_Int32 getXAxisTypeByChartType(sal_Int32 eChartType)
3092{
3093 if( (eChartType == chart::TYPEID_SCATTER)
3094 || (eChartType == chart::TYPEID_BUBBLE) )
3095 return XML_valAx;
3096 else if( eChartType == chart::TYPEID_STOCK )
3097 return XML_dateAx;
3098
3099 return XML_catAx;
3100}
3101
3102sal_Int32 getRealXAxisType(sal_Int32 nAxisType)
3103{
3104 if( nAxisType == chart2::AxisType::CATEGORY )
3105 return XML_catAx;
3106 else if( nAxisType == chart2::AxisType::DATE )
3107 return XML_dateAx;
3108 else if( nAxisType == chart2::AxisType::SERIES )
3109 return XML_serAx;
3110
3111 return XML_valAx;
3112}
3113
3114}
3115
3116void ChartExport::exportAxis(const AxisIdPair& rAxisIdPair)
3117{
3118 // get some properties from document first
3119 bool bHasXAxisTitle = false,
3120 bHasYAxisTitle = false,
3121 bHasZAxisTitle = false,
3122 bHasSecondaryXAxisTitle = false,
3123 bHasSecondaryYAxisTitle = false;
3124 bool bHasXAxisMajorGrid = false,
3125 bHasXAxisMinorGrid = false,
3126 bHasYAxisMajorGrid = false,
3127 bHasYAxisMinorGrid = false,
3128 bHasZAxisMajorGrid = false,
3129 bHasZAxisMinorGrid = false;
3130
3131 Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
3132
3133 xDiagramProperties->getPropertyValue("HasXAxisTitle") >>= bHasXAxisTitle;
3134 xDiagramProperties->getPropertyValue("HasYAxisTitle") >>= bHasYAxisTitle;
3135 xDiagramProperties->getPropertyValue("HasZAxisTitle") >>= bHasZAxisTitle;
3136 xDiagramProperties->getPropertyValue("HasSecondaryXAxisTitle") >>= bHasSecondaryXAxisTitle;
3137 xDiagramProperties->getPropertyValue("HasSecondaryYAxisTitle") >>= bHasSecondaryYAxisTitle;
3138
3139 xDiagramProperties->getPropertyValue("HasXAxisGrid") >>= bHasXAxisMajorGrid;
3140 xDiagramProperties->getPropertyValue("HasYAxisGrid") >>= bHasYAxisMajorGrid;
3141 xDiagramProperties->getPropertyValue("HasZAxisGrid") >>= bHasZAxisMajorGrid;
3142
3143 xDiagramProperties->getPropertyValue("HasXAxisHelpGrid") >>= bHasXAxisMinorGrid;
3144 xDiagramProperties->getPropertyValue("HasYAxisHelpGrid") >>= bHasYAxisMinorGrid;
3145 xDiagramProperties->getPropertyValue("HasZAxisHelpGrid") >>= bHasZAxisMinorGrid;
3146
3147 Reference< XPropertySet > xAxisProp;
3151 sal_Int32 nAxisType = XML_catAx;
3152 const char* sAxPos = nullptr;
3153
3154 switch( rAxisIdPair.nAxisType )
3155 {
3156 case AXIS_PRIMARY_X:
3157 {
3158 Reference< css::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
3159 if( xAxisXSupp.is())
3160 xAxisProp = xAxisXSupp->getXAxis();
3161 if( bHasXAxisTitle )
3162 xAxisTitle = xAxisXSupp->getXAxisTitle();
3163 if( bHasXAxisMajorGrid )
3164 xMajorGrid = xAxisXSupp->getXMainGrid();
3165 if( bHasXAxisMinorGrid )
3166 xMinorGrid = xAxisXSupp->getXHelpGrid();
3167
3168 nAxisType = lcl_getCategoryAxisType(mxNewDiagram, 0, 0);
3169 if( nAxisType != -1 )
3170 nAxisType = getRealXAxisType(nAxisType);
3171 else
3172 nAxisType = getXAxisTypeByChartType( getChartType() );
3173 // FIXME: axPos, need to check axis direction
3174 sAxPos = "b";
3175 break;
3176 }
3177 case AXIS_PRIMARY_Y:
3178 {
3179 Reference< css::chart::XAxisYSupplier > xAxisYSupp( mxDiagram, uno::UNO_QUERY );
3180 if( xAxisYSupp.is())
3181 xAxisProp = xAxisYSupp->getYAxis();
3182 if( bHasYAxisTitle )
3183 xAxisTitle = xAxisYSupp->getYAxisTitle();
3184 if( bHasYAxisMajorGrid )
3185 xMajorGrid = xAxisYSupp->getYMainGrid();
3186 if( bHasYAxisMinorGrid )
3187 xMinorGrid = xAxisYSupp->getYHelpGrid();
3188
3189 nAxisType = XML_valAx;
3190 // FIXME: axPos, need to check axis direction
3191 sAxPos = "l";
3192 break;
3193 }
3194 case AXIS_PRIMARY_Z:
3195 {
3196 Reference< css::chart::XAxisZSupplier > xAxisZSupp( mxDiagram, uno::UNO_QUERY );
3197 if( xAxisZSupp.is())
3198 xAxisProp = xAxisZSupp->getZAxis();
3199 if( bHasZAxisTitle )
3200 xAxisTitle = xAxisZSupp->getZAxisTitle();
3201 if( bHasZAxisMajorGrid )
3202 xMajorGrid = xAxisZSupp->getZMainGrid();
3203 if( bHasZAxisMinorGrid )
3204 xMinorGrid = xAxisZSupp->getZHelpGrid();
3205
3206 sal_Int32 eChartType = getChartType( );
3207 if( (eChartType == chart::TYPEID_SCATTER)
3208 || (eChartType == chart::TYPEID_BUBBLE) )
3209 nAxisType = XML_valAx;
3210 else if( eChartType == chart::TYPEID_STOCK )
3211 nAxisType = XML_dateAx;
3212 else if( eChartType == chart::TYPEID_BAR || eChartType == chart::TYPEID_AREA )
3213 nAxisType = XML_serAx;
3214 // FIXME: axPos, need to check axis direction
3215 sAxPos = "b";
3216 break;
3217 }
3218 case AXIS_SECONDARY_X:
3219 {
3220 Reference< css::chart::XTwoAxisXSupplier > xAxisTwoXSupp( mxDiagram, uno::UNO_QUERY );
3221 if( xAxisTwoXSupp.is())
3222 xAxisProp = xAxisTwoXSupp->getSecondaryXAxis();
3223 if( bHasSecondaryXAxisTitle )
3224 {
3226 xAxisTitle = xAxisSupp->getSecondXAxisTitle();
3227 }
3228
3229 nAxisType = lcl_getCategoryAxisType(mxNewDiagram, 0, 1);
3230 if( nAxisType != -1 )
3231 nAxisType = getRealXAxisType(nAxisType);
3232 else
3233 nAxisType = getXAxisTypeByChartType( getChartType() );
3234 // FIXME: axPos, need to check axis direction
3235 sAxPos = "t";
3236 break;
3237 }
3238 case AXIS_SECONDARY_Y:
3239 {
3240 Reference< css::chart::XTwoAxisYSupplier > xAxisTwoYSupp( mxDiagram, uno::UNO_QUERY );
3241 if( xAxisTwoYSupp.is())
3242 xAxisProp = xAxisTwoYSupp->getSecondaryYAxis();
3243 if( bHasSecondaryYAxisTitle )
3244 {
3246 xAxisTitle = xAxisSupp->getSecondYAxisTitle();
3247 }
3248
3249 nAxisType = XML_valAx;
3250 // FIXME: axPos, need to check axis direction
3251 sAxPos = "r";
3252 break;
3253 }
3254 }
3255
3256 _exportAxis(xAxisProp, xAxisTitle, xMajorGrid, xMinorGrid, nAxisType, sAxPos, rAxisIdPair);
3257}
3258
3260 const Reference< XPropertySet >& xAxisProp,
3261 const Reference< drawing::XShape >& xAxisTitle,
3262 const Reference< XPropertySet >& xMajorGrid,
3263 const Reference< XPropertySet >& xMinorGrid,
3264 sal_Int32 nAxisType,
3265 const char* sAxisPos,
3266 const AxisIdPair& rAxisIdPair )
3267{
3268 FSHelperPtr pFS = GetFS();
3269 pFS->startElement(FSNS(XML_c, nAxisType));
3270 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(rAxisIdPair.nAxisId));
3271
3272 pFS->startElement(FSNS(XML_c, XML_scaling));
3273
3274 // logBase, min, max
3275 if(GetProperty( xAxisProp, "Logarithmic" ) )
3276 {
3277 bool bLogarithmic = false;
3278 mAny >>= bLogarithmic;
3279 if( bLogarithmic )
3280 {
3281 // default value is 10?
3282 pFS->singleElement(FSNS(XML_c, XML_logBase), XML_val, OString::number(10));
3283 }
3284 }
3285
3286 // orientation: minMax, maxMin
3287 bool bReverseDirection = false;
3288 if(GetProperty( xAxisProp, "ReverseDirection" ) )
3289 mAny >>= bReverseDirection;
3290
3291 const char* orientation = bReverseDirection ? "maxMin":"minMax";
3292 pFS->singleElement(FSNS(XML_c, XML_orientation), XML_val, orientation);
3293
3294 bool bAutoMax = false;
3295 if(GetProperty( xAxisProp, "AutoMax" ) )
3296 mAny >>= bAutoMax;
3297
3298 if( !bAutoMax && (GetProperty( xAxisProp, "Max" ) ) )
3299 {
3300 double dMax = 0;
3301 mAny >>= dMax;
3302 pFS->singleElement(FSNS(XML_c, XML_max), XML_val, OString::number(dMax));
3303 }
3304
3305 bool bAutoMin = false;
3306 if(GetProperty( xAxisProp, "AutoMin" ) )
3307 mAny >>= bAutoMin;
3308
3309 if( !bAutoMin && (GetProperty( xAxisProp, "Min" ) ) )
3310 {
3311 double dMin = 0;
3312 mAny >>= dMin;
3313 pFS->singleElement(FSNS(XML_c, XML_min), XML_val, OString::number(dMin));
3314 }
3315
3316 pFS->endElement( FSNS( XML_c, XML_scaling ) );
3317
3318 bool bVisible = true;
3319 if( xAxisProp.is() )
3320 {
3321 xAxisProp->getPropertyValue("Visible") >>= bVisible;
3322 }
3323
3324 // only export each axis only once non-deleted
3325 bool bDeleted = maExportedAxis.find(rAxisIdPair.nAxisType) != maExportedAxis.end();
3326
3327 if (!bDeleted)
3328 maExportedAxis.insert(rAxisIdPair.nAxisType);
3329
3330 pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, !bDeleted && bVisible ? "0" : "1");
3331
3332 // FIXME: axPos, need to check the property "ReverseDirection"
3333 pFS->singleElement(FSNS(XML_c, XML_axPos), XML_val, sAxisPos);
3334 // major grid line
3335 if( xMajorGrid.is())
3336 {
3337 pFS->startElement(FSNS(XML_c, XML_majorGridlines));
3338 exportShapeProps( xMajorGrid );
3339 pFS->endElement( FSNS( XML_c, XML_majorGridlines ) );
3340 }
3341
3342 // minor grid line
3343 if( xMinorGrid.is())
3344 {
3345 pFS->startElement(FSNS(XML_c, XML_minorGridlines));
3346 exportShapeProps( xMinorGrid );
3347 pFS->endElement( FSNS( XML_c, XML_minorGridlines ) );
3348 }
3349
3350 // title
3351 if( xAxisTitle.is() )
3352 exportTitle( xAxisTitle );
3353
3354 bool bLinkedNumFmt = true;
3355 if (GetProperty(xAxisProp, "LinkNumberFormatToSource"))
3356 mAny >>= bLinkedNumFmt;
3357
3358 OUString aNumberFormatString("General");
3359 if (GetProperty(xAxisProp, "NumberFormat"))
3360 {
3361 sal_Int32 nKey = 0;
3362 mAny >>= nKey;
3363 aNumberFormatString = getNumberFormatCode(nKey);
3364 }
3365
3366 pFS->singleElement(FSNS(XML_c, XML_numFmt),
3367 XML_formatCode, aNumberFormatString,
3368 XML_sourceLinked, bLinkedNumFmt ? "1" : "0");
3369
3370 // majorTickMark
3371 sal_Int32 nValue = 0;
3372 if(GetProperty( xAxisProp, "Marks" ) )
3373 {
3374 mAny >>= nValue;
3375 bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
3376 bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
3377 const char* majorTickMark = nullptr;
3378 if( bInner && bOuter )
3379 majorTickMark = "cross";
3380 else if( bInner )
3381 majorTickMark = "in";
3382 else if( bOuter )
3383 majorTickMark = "out";
3384 else
3385 majorTickMark = "none";
3386 pFS->singleElement(FSNS(XML_c, XML_majorTickMark), XML_val, majorTickMark);
3387 }
3388 // minorTickMark
3389 if(GetProperty( xAxisProp, "HelpMarks" ) )
3390 {
3391 mAny >>= nValue;
3392 bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
3393 bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
3394 const char* minorTickMark = nullptr;
3395 if( bInner && bOuter )
3396 minorTickMark = "cross";
3397 else if( bInner )
3398 minorTickMark = "in";
3399 else if( bOuter )
3400 minorTickMark = "out";
3401 else
3402 minorTickMark = "none";
3403 pFS->singleElement(FSNS(XML_c, XML_minorTickMark), XML_val, minorTickMark);
3404 }
3405 // tickLblPos
3406 const char* sTickLblPos = nullptr;
3407 bool bDisplayLabel = true;
3408 if(GetProperty( xAxisProp, "DisplayLabels" ) )
3409 mAny >>= bDisplayLabel;
3410 if( bDisplayLabel && (GetProperty( xAxisProp, "LabelPosition" ) ) )
3411 {
3412 css::chart::ChartAxisLabelPosition eLabelPosition = css::chart::ChartAxisLabelPosition_NEAR_AXIS;
3413 mAny >>= eLabelPosition;
3414 switch( eLabelPosition )
3415 {
3416 case css::chart::ChartAxisLabelPosition_NEAR_AXIS:
3417 case css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE:
3418 sTickLblPos = "nextTo";
3419 break;
3420 case css::chart::ChartAxisLabelPosition_OUTSIDE_START:
3421 sTickLblPos = "low";
3422 break;
3423 case css::chart::ChartAxisLabelPosition_OUTSIDE_END:
3424 sTickLblPos = "high";
3425 break;
3426 default:
3427 sTickLblPos = "nextTo";
3428 break;
3429 }
3430 }
3431 else
3432 {
3433 sTickLblPos = "none";
3434 }
3435 pFS->singleElement(FSNS(XML_c, XML_tickLblPos), XML_val, sTickLblPos);
3436
3437 // shape properties
3438 exportShapeProps( xAxisProp );
3439
3440 exportTextProps(xAxisProp);
3441
3442 pFS->singleElement(FSNS(XML_c, XML_crossAx), XML_val, OString::number(rAxisIdPair.nCrossAx));
3443
3444 // crosses & crossesAt
3445 bool bCrossesValue = false;
3446 const char* sCrosses = nullptr;
3447 // do not export the CrossoverPosition/CrossoverValue, if the axis is deleted and not visible
3448 if( GetProperty( xAxisProp, "CrossoverPosition" ) && !bDeleted && bVisible )
3449 {
3450 css::chart::ChartAxisPosition ePosition( css::chart::ChartAxisPosition_ZERO );
3451 mAny >>= ePosition;
3452 switch( ePosition )
3453 {
3454 case css::chart::ChartAxisPosition_START:
3455 sCrosses = "min";
3456 break;
3457 case css::chart::ChartAxisPosition_END:
3458 sCrosses = "max";
3459 break;
3460 case css::chart::ChartAxisPosition_ZERO:
3461 sCrosses = "autoZero";
3462 break;
3463 default:
3464 bCrossesValue = true;
3465 break;
3466 }
3467 }
3468
3469 if( bCrossesValue && GetProperty( xAxisProp, "CrossoverValue" ) )
3470 {
3471 double dValue = 0;
3472 mAny >>= dValue;
3473 pFS->singleElement(FSNS(XML_c, XML_crossesAt), XML_val, OString::number(dValue));
3474 }
3475 else
3476 {
3477 if(sCrosses)
3478 {
3479 pFS->singleElement(FSNS(XML_c, XML_crosses), XML_val, sCrosses);
3480 }
3481 }
3482
3483 if( ( nAxisType == XML_catAx )
3484 || ( nAxisType == XML_dateAx ) )
3485 {
3486 // FIXME: seems not support? use default value,
3487 const char* const isAuto = "1";
3488 pFS->singleElement(FSNS(XML_c, XML_auto), XML_val, isAuto);
3489
3490 if( nAxisType == XML_catAx )
3491 {
3492 // FIXME: seems not support? lblAlgn
3493 const char* const sLblAlgn = "ctr";
3494 pFS->singleElement(FSNS(XML_c, XML_lblAlgn), XML_val, sLblAlgn);
3495 }
3496
3497 // FIXME: seems not support? lblOffset
3498 pFS->singleElement(FSNS(XML_c, XML_lblOffset), XML_val, OString::number(100));
3499
3500 // export baseTimeUnit, majorTimeUnit, minorTimeUnit of Date axis
3501 if( nAxisType == XML_dateAx )
3502 {
3503 sal_Int32 nAxisIndex = -1;
3504 if( rAxisIdPair.nAxisType == AXIS_PRIMARY_X )
3505 nAxisIndex = 0;
3506 else if( rAxisIdPair.nAxisType == AXIS_SECONDARY_X )
3507 nAxisIndex = 1;
3508
3509 cssc::TimeIncrement aTimeIncrement = lcl_getDateTimeIncrement( mxNewDiagram, nAxisIndex );
3510 sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY;
3511 if( aTimeIncrement.TimeResolution >>= nTimeResolution )
3512 pFS->singleElement(FSNS(XML_c, XML_baseTimeUnit), XML_val, lclGetTimeUnitToken(nTimeResolution));
3513
3514 cssc::TimeInterval aInterval;
3515 if( aTimeIncrement.MajorTimeInterval >>= aInterval )
3516 {
3517 pFS->singleElement(FSNS(XML_c, XML_majorUnit), XML_val, OString::number(aInterval.Number));
3518 pFS->singleElement(FSNS(XML_c, XML_majorTimeUnit), XML_val, lclGetTimeUnitToken(aInterval.TimeUnit));
3519 }
3520 if( aTimeIncrement.MinorTimeInterval >>= aInterval )
3521 {
3522 pFS->singleElement(FSNS(XML_c, XML_minorUnit), XML_val, OString::number(aInterval.Number));
3523 pFS->singleElement(FSNS(XML_c, XML_minorTimeUnit), XML_val, lclGetTimeUnitToken(aInterval.TimeUnit));
3524 }
3525 }
3526
3527 // FIXME: seems not support? noMultiLvlLbl
3528 pFS->singleElement(FSNS(XML_c, XML_noMultiLvlLbl), XML_val, OString::number(0));
3529 }
3530
3531 // crossBetween
3532 if( nAxisType == XML_valAx )
3533 {
3535 pFS->singleElement(FSNS(XML_c, XML_crossBetween), XML_val, "between");
3536 else
3537 pFS->singleElement(FSNS(XML_c, XML_crossBetween), XML_val, "midCat");
3538 }
3539
3540 // majorUnit
3541 bool bAutoStepMain = false;
3542 if(GetProperty( xAxisProp, "AutoStepMain" ) )
3543 mAny >>= bAutoStepMain;
3544
3545 if( !bAutoStepMain && (GetProperty( xAxisProp, "StepMain" ) ) )
3546 {
3547 double dMajorUnit = 0;
3548 mAny >>= dMajorUnit;
3549 pFS->singleElement(FSNS(XML_c, XML_majorUnit), XML_val, OString::number(dMajorUnit));
3550 }
3551 // minorUnit
3552 bool bAutoStepHelp = false;
3553 if(GetProperty( xAxisProp, "AutoStepHelp" ) )
3554 mAny >>= bAutoStepHelp;
3555
3556 if( !bAutoStepHelp && (GetProperty( xAxisProp, "StepHelp" ) ) )
3557 {
3558 double dMinorUnit = 0;
3559 mAny >>= dMinorUnit;
3560 if( GetProperty( xAxisProp, "StepHelpCount" ) )
3561 {
3562 sal_Int32 dMinorUnitCount = 0;
3563 mAny >>= dMinorUnitCount;
3564 // tdf#114168 Don't save minor unit if number of step help count is 5 (which is default for MS Excel),
3565 // to allow proper .xlsx import. If minorUnit is set and majorUnit not, then it is impossible
3566 // to calculate StepHelpCount.
3567 if( dMinorUnitCount != 5 )
3568 {
3569 pFS->singleElement( FSNS( XML_c, XML_minorUnit ),
3570 XML_val, OString::number( dMinorUnit ) );
3571 }
3572 }
3573 }
3574
3575 if( nAxisType == XML_valAx && GetProperty( xAxisProp, "DisplayUnits" ) )
3576 {
3577 bool bDisplayUnits = false;
3578 mAny >>= bDisplayUnits;
3579 if(bDisplayUnits)
3580 {
3581 if(GetProperty( xAxisProp, "BuiltInUnit" ))
3582 {
3583 OUString aVal;
3584 mAny >>= aVal;
3585 if(!aVal.isEmpty())
3586 {
3587 pFS->startElement(FSNS(XML_c, XML_dispUnits));
3588
3589 pFS->singleElement(FSNS(XML_c, XML_builtInUnit), XML_val, aVal);
3590
3591 pFS->singleElement(FSNS( XML_c, XML_dispUnitsLbl ));
3592 pFS->endElement( FSNS( XML_c, XML_dispUnits ) );
3593 }
3594 }
3595 }
3596 }
3597
3598 pFS->endElement( FSNS( XML_c, nAxisType ) );
3599}
3600
3601namespace {
3602
3603struct LabelPlacementParam
3604{
3606 sal_Int32 meDefault;
3607
3608 std::unordered_set<sal_Int32> maAllowedValues;
3609
3610 LabelPlacementParam(bool bExport, sal_Int32 nDefault) :
3611 mbExport(bExport),
3612 meDefault(nDefault),
3614 {
3615 css::chart::DataLabelPlacement::OUTSIDE,
3616 css::chart::DataLabelPlacement::INSIDE,
3617 css::chart::DataLabelPlacement::CENTER,
3618 css::chart::DataLabelPlacement::NEAR_ORIGIN,
3619 css::chart::DataLabelPlacement::TOP,
3620 css::chart::DataLabelPlacement::BOTTOM,
3621 css::chart::DataLabelPlacement::LEFT,
3622 css::chart::DataLabelPlacement::RIGHT,
3623 css::chart::DataLabelPlacement::AVOID_OVERLAP
3624 }
3625 )
3626 {}
3627};
3628
3629const char* toOOXMLPlacement( sal_Int32 nPlacement )
3630{
3631 switch (nPlacement)
3632 {
3633 case css::chart::DataLabelPlacement::OUTSIDE: return "outEnd";
3634 case css::chart::DataLabelPlacement::INSIDE: return "inEnd";
3635 case css::chart::DataLabelPlacement::CENTER: return "ctr";
3636 case css::chart::DataLabelPlacement::NEAR_ORIGIN: return "inBase";
3637 case css::chart::DataLabelPlacement::TOP: return "t";
3638 case css::chart::DataLabelPlacement::BOTTOM: return "b";
3639 case css::chart::DataLabelPlacement::LEFT: return "l";
3640 case css::chart::DataLabelPlacement::RIGHT: return "r";
3641 case css::chart::DataLabelPlacement::CUSTOM:
3642 case css::chart::DataLabelPlacement::AVOID_OVERLAP: return "bestFit";
3643 default:
3644 ;
3645 }
3646
3647 return "outEnd";
3648}
3649
3650OUString getFieldTypeString( const chart2::DataPointCustomLabelFieldType aType )
3651{
3652 switch (aType)
3653 {
3654 case chart2::DataPointCustomLabelFieldType_CATEGORYNAME:
3655 return "CATEGORYNAME";
3656
3657 case chart2::DataPointCustomLabelFieldType_SERIESNAME:
3658 return "SERIESNAME";
3659
3660 case chart2::DataPointCustomLabelFieldType_VALUE:
3661 return "VALUE";
3662
3663 case chart2::DataPointCustomLabelFieldType_CELLREF:
3664 return "CELLREF";
3665
3666 case chart2::DataPointCustomLabelFieldType_CELLRANGE:
3667 return "CELLRANGE";
3668
3669 default:
3670 break;
3671 }
3672 return OUString();
3673}
3674
3675void writeRunProperties( ChartExport* pChartExport, Reference<XPropertySet> const & xPropertySet )
3676{
3677 bool bDummy = false;
3678 sal_Int32 nDummy;
3679 pChartExport->WriteRunProperties(xPropertySet, false, XML_rPr, true, bDummy, nDummy);
3680}
3681
3682void writeCustomLabel( const FSHelperPtr& pFS, ChartExport* pChartExport,
3683 const Sequence<Reference<chart2::XDataPointCustomLabelField>>& rCustomLabelFields,
3684 sal_Int32 nLabelIndex, DataLabelsRange& rDLblsRange )
3685{
3686 pFS->startElement(FSNS(XML_c, XML_tx));
3687 pFS->startElement(FSNS(XML_c, XML_rich));
3688
3689 // TODO: body properties?
3690 pFS->singleElement(FSNS(XML_a, XML_bodyPr));
3691
3692 OUString sFieldType;
3693 OUString sContent;
3694 pFS->startElement(FSNS(XML_a, XML_p));
3695
3696 for (auto& rField : rCustomLabelFields)
3697 {
3698 Reference<XPropertySet> xPropertySet(rField, UNO_QUERY);
3699 chart2::DataPointCustomLabelFieldType aType = rField->getFieldType();
3700 sFieldType.clear();
3701 sContent.clear();
3702 bool bNewParagraph = false;
3703
3704 if (aType == chart2::DataPointCustomLabelFieldType_CELLRANGE &&
3705 rField->getDataLabelsRange())
3706 {
3707 if (rDLblsRange.getRange().isEmpty())
3708 rDLblsRange.setRange(rField->getCellRange());
3709
3710 if (!rDLblsRange.hasLabel(nLabelIndex))
3711 rDLblsRange.setLabel(nLabelIndex, rField->getString());
3712
3713 sContent = "[CELLRANGE]";
3714 }
3715 else
3716 {
3717 sContent = rField->getString();
3718 }
3719
3720 if (aType == chart2::DataPointCustomLabelFieldType_NEWLINE)
3721 bNewParagraph = true;
3722 else if (aType != chart2::DataPointCustomLabelFieldType_TEXT)
3723 sFieldType = getFieldTypeString(aType);
3724
3725 if (bNewParagraph)
3726 {
3727 pFS->endElement(FSNS(XML_a, XML_p));
3728 pFS->startElement(FSNS(XML_a, XML_p));
3729 continue;
3730 }
3731
3732 if (sFieldType.isEmpty())
3733 {
3734 // Normal text run
3735 pFS->startElement(FSNS(XML_a, XML_r));
3736 writeRunProperties(pChartExport, xPropertySet);
3737
3738 pFS->startElement(FSNS(XML_a, XML_t));
3739 pFS->writeEscaped(sContent);
3740 pFS->endElement(FSNS(XML_a, XML_t));
3741
3742 pFS->endElement(FSNS(XML_a, XML_r));
3743 }
3744 else
3745 {
3746 // Field
3747 pFS->startElement(FSNS(XML_a, XML_fld), XML_id, rField->getGuid(), XML_type,
3748 sFieldType);
3749 writeRunProperties(pChartExport, xPropertySet);
3750
3751 pFS->startElement(FSNS(XML_a, XML_t));
3752 pFS->writeEscaped(sContent);
3753 pFS->endElement(FSNS(XML_a, XML_t));
3754
3755 pFS->endElement(FSNS(XML_a, XML_fld));
3756 }
3757 }
3758
3759 pFS->endElement(FSNS(XML_a, XML_p));
3760 pFS->endElement(FSNS(XML_c, XML_rich));
3761 pFS->endElement(FSNS(XML_c, XML_tx));
3762}
3763
3764void writeLabelProperties( const FSHelperPtr& pFS, ChartExport* pChartExport,
3765 const uno::Reference<beans::XPropertySet>& xPropSet, const LabelPlacementParam& rLabelParam,
3766 sal_Int32 nLabelIndex, DataLabelsRange& rDLblsRange )
3767{
3768 if (!xPropSet.is())
3769 return;
3770
3771 chart2::DataPointLabel aLabel;
3772 Sequence<Reference<chart2::XDataPointCustomLabelField>> aCustomLabelFields;
3773 sal_Int32 nLabelBorderWidth = 0;
3774 sal_Int32 nLabelBorderColor = 0x00FFFFFF;
3775 sal_Int32 nLabelFillColor = -1;
3776
3777 xPropSet->getPropertyValue("Label") >>= aLabel;
3778 xPropSet->getPropertyValue("CustomLabelFields") >>= aCustomLabelFields;
3779 xPropSet->getPropertyValue("LabelBorderWidth") >>= nLabelBorderWidth;
3780 xPropSet->getPropertyValue("LabelBorderColor") >>= nLabelBorderColor;
3781 xPropSet->getPropertyValue("LabelFillColor") >>= nLabelFillColor;
3782
3783 if (nLabelBorderWidth > 0 || nLabelFillColor != -1)
3784 {
3785 pFS->startElement(FSNS(XML_c, XML_spPr));
3786
3787 if (nLabelFillColor != -1)
3788 {
3789 pFS->startElement(FSNS(XML_a, XML_solidFill));
3790
3791 OString aStr = OString::number(nLabelFillColor, 16).toAsciiUpperCase();
3792 pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr);
3793
3794 pFS->endElement(FSNS(XML_a, XML_solidFill));
3795 }
3796
3797 if (nLabelBorderWidth > 0)
3798 {
3799 pFS->startElement(FSNS(XML_a, XML_ln), XML_w,
3800 OString::number(convertHmmToEmu(nLabelBorderWidth)));
3801
3802 if (nLabelBorderColor != -1)
3803 {
3804 pFS->startElement(FSNS(XML_a, XML_solidFill));
3805
3806 OString aStr = OString::number(nLabelBorderColor, 16).toAsciiUpperCase();
3807 pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr);
3808
3809 pFS->endElement(FSNS(XML_a, XML_solidFill));
3810 }
3811
3812 pFS->endElement(FSNS(XML_a, XML_ln));
3813 }
3814
3815 pFS->endElement(FSNS(XML_c, XML_spPr));
3816 }
3817
3818 pChartExport->exportTextProps(xPropSet);
3819
3820 if (aCustomLabelFields.hasElements())
3821 writeCustomLabel(pFS, pChartExport, aCustomLabelFields, nLabelIndex, rDLblsRange);
3822
3823 if (rLabelParam.mbExport)
3824 {
3825 sal_Int32 nLabelPlacement = rLabelParam.meDefault;
3826 if (xPropSet->getPropertyValue("LabelPlacement") >>= nLabelPlacement)
3827 {
3828 if (!rLabelParam.maAllowedValues.count(nLabelPlacement))
3829 nLabelPlacement = rLabelParam.meDefault;
3830 pFS->singleElement(FSNS(XML_c, XML_dLblPos), XML_val, toOOXMLPlacement(nLabelPlacement));
3831 }
3832 }
3833
3834 pFS->singleElement(FSNS(XML_c, XML_showLegendKey), XML_val, ToPsz10(aLabel.ShowLegendSymbol));
3835 pFS->singleElement(FSNS(XML_c, XML_showVal), XML_val, ToPsz10(aLabel.ShowNumber));
3836 pFS->singleElement(FSNS(XML_c, XML_showCatName), XML_val, ToPsz10(aLabel.ShowCategoryName));
3837 pFS->singleElement(FSNS(XML_c, XML_showSerName), XML_val, ToPsz10(aLabel.ShowSeriesName));
3838 pFS->singleElement(FSNS(XML_c, XML_showPercent), XML_val, ToPsz10(aLabel.ShowNumberInPercent));
3839
3840 // Export the text "separator" if exists
3841 uno::Any aAny = xPropSet->getPropertyValue("LabelSeparator");
3842 if( aAny.hasValue() )
3843 {
3844 OUString nLabelSeparator;
3845 aAny >>= nLabelSeparator;
3846 pFS->startElement(FSNS(XML_c, XML_separator));
3847 pFS->writeEscaped( nLabelSeparator );
3848 pFS->endElement( FSNS( XML_c, XML_separator ) );
3849 }
3850
3851 if (rDLblsRange.hasLabel(nLabelIndex))
3852 {
3853 pFS->startElement(FSNS(XML_c, XML_extLst));
3854 pFS->startElement(FSNS(XML_c, XML_ext), XML_uri,
3855 "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}", FSNS(XML_xmlns, XML_c15),
3856 pChartExport->GetFB()->getNamespaceURL(OOX_NS(c15)));
3857
3858 pFS->singleElement(FSNS(XML_c15, XML_showDataLabelsRange), XML_val, "1");
3859
3860 pFS->endElement(FSNS(XML_c, XML_ext));
3861 pFS->endElement(FSNS(XML_c, XML_extLst));
3862 }
3863}
3864
3865}
3866
3868 const uno::Reference<chart2::XDataSeries> & xSeries, sal_Int32 nSeriesLength, sal_Int32 eChartType,
3869 DataLabelsRange& rDLblsRange)
3870{
3871 if (!xSeries.is() || nSeriesLength <= 0)
3872 return;
3873
3874 uno::Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
3875 if (!xPropSet.is())
3876 return;
3877
3878 FSHelperPtr pFS = GetFS();
3879 pFS->startElement(FSNS(XML_c, XML_dLbls));
3880
3881 bool bLinkedNumFmt = true;
3882 if (GetProperty(xPropSet, "LinkNumberFormatToSource"))
3883 mAny >>= bLinkedNumFmt;
3884
3885 chart2::DataPointLabel aLabel;
3886 bool bLabelIsNumberFormat = true;
3887 if( xPropSet->getPropertyValue("Label") >>= aLabel )
3888 bLabelIsNumberFormat = aLabel.ShowNumber;
3889
3890 if (GetProperty(xPropSet, bLabelIsNumberFormat ? OUString("NumberFormat") : OUString("PercentageNumberFormat")))
3891 {
3892 sal_Int32 nKey = 0;
3893 mAny >>= nKey;
3894
3895 OUString aNumberFormatString = getNumberFormatCode(nKey);
3896
3897 pFS->singleElement(FSNS(XML_c, XML_numFmt),
3898 XML_formatCode, aNumberFormatString,
3899 XML_sourceLinked, ToPsz10(bLinkedNumFmt));
3900 }
3901
3902 uno::Sequence<sal_Int32> aAttrLabelIndices;
3903 xPropSet->getPropertyValue("AttributedDataPoints") >>= aAttrLabelIndices;
3904
3905 // We must not export label placement property when the chart type doesn't
3906 // support this option in MS Office, else MS Office would think the file
3907 // is corrupt & refuse to open it.
3908
3909 const chart::TypeGroupInfo& rInfo = chart::GetTypeGroupInfo(static_cast<chart::TypeId>(eChartType));
3910 LabelPlacementParam aParam(!mbIs3DChart, rInfo.mnDefLabelPos);
3911 switch (eChartType) // diagram chart type
3912 {
3913 case chart::TYPEID_PIE:
3915 aParam.mbExport = false;
3916 else
3917 // All pie charts support label placement.
3918 aParam.mbExport = true;
3919 break;
3920 case chart::TYPEID_AREA:
3923 // These chart types don't support label placement.
3924 aParam.mbExport = false;
3925 break;
3926 case chart::TYPEID_BAR:
3927 if (mbStacked || mbPercent)
3928 {
3929 aParam.maAllowedValues.clear();
3930 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3931 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3932 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3933 aParam.meDefault = css::chart::DataLabelPlacement::CENTER;
3934 }
3935 else // Clustered bar chart
3936 {
3937 aParam.maAllowedValues.clear();
3938 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3939 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3940 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::OUTSIDE);
3941 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3942 aParam.meDefault = css::chart::DataLabelPlacement::OUTSIDE;
3943 }
3944 break;
3945 default:
3946 ;
3947 }
3948
3949 for (const sal_Int32 nIdx : std::as_const(aAttrLabelIndices))
3950 {
3951 uno::Reference<beans::XPropertySet> xLabelPropSet = xSeries->getDataPointByIndex(nIdx);
3952
3953 if (!xLabelPropSet.is())
3954 continue;
3955
3956 pFS->startElement(FSNS(XML_c, XML_dLbl));
3957 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nIdx));
3958
3959 // export custom position of data label
3960 if( eChartType != chart::TYPEID_PIE )
3961 {
3962 chart2::RelativePosition aCustomLabelPosition;
3963 if( xLabelPropSet->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition )
3964 {
3965 pFS->startElement(FSNS(XML_c, XML_layout));
3966 pFS->startElement(FSNS(XML_c, XML_manualLayout));
3967
3968 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(aCustomLabelPosition.Primary));
3969 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(aCustomLabelPosition.Secondary));
3970
3971 SAL_WARN_IF(aCustomLabelPosition.Anchor != css::drawing::Alignment_TOP_LEFT, "oox", "unsupported anchor position");
3972
3973 pFS->endElement(FSNS(XML_c, XML_manualLayout));
3974 pFS->endElement(FSNS(XML_c, XML_layout));
3975 }
3976 }
3977
3978 if( GetProperty(xLabelPropSet, "LinkNumberFormatToSource") )
3979 mAny >>= bLinkedNumFmt;
3980
3981 if( xLabelPropSet->getPropertyValue("Label") >>= aLabel )
3982 bLabelIsNumberFormat = aLabel.ShowNumber;
3983 else
3984 bLabelIsNumberFormat = true;
3985
3986 if (GetProperty(xLabelPropSet, bLabelIsNumberFormat ? OUString("NumberFormat") : OUString("PercentageNumberFormat")))
3987 {
3988 sal_Int32 nKey = 0;
3989 mAny >>= nKey;
3990
3991 OUString aNumberFormatString = getNumberFormatCode(nKey);
3992
3993 pFS->singleElement(FSNS(XML_c, XML_numFmt), XML_formatCode, aNumberFormatString,
3994 XML_sourceLinked, ToPsz10(bLinkedNumFmt));
3995 }
3996
3997 // Individual label property that overwrites the baseline.
3998 writeLabelProperties(pFS, this, xLabelPropSet, aParam, nIdx, rDLblsRange);
3999 pFS->endElement(FSNS(XML_c, XML_dLbl));
4000 }
4001
4002 // Baseline label properties for all labels.
4003 writeLabelProperties(pFS, this, xPropSet, aParam, -1, rDLblsRange);
4004
4005 bool bShowLeaderLines = false;
4006 xPropSet->getPropertyValue("ShowCustomLeaderLines") >>= bShowLeaderLines;
4007 pFS->singleElement(FSNS(XML_c, XML_showLeaderLines), XML_val, ToPsz10(bShowLeaderLines));
4008
4009 // Export leader line
4010 if( eChartType != chart::TYPEID_PIE )
4011 {
4012 pFS->startElement(FSNS(XML_c, XML_extLst));
4013 pFS->startElement(FSNS(XML_c, XML_ext), XML_uri, "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}", FSNS(XML_xmlns, XML_c15), GetFB()->getNamespaceURL(OOX_NS(c15)));
4014 pFS->singleElement(FSNS(XML_c15, XML_showLeaderLines), XML_val, ToPsz10(bShowLeaderLines));
4015 pFS->endElement(FSNS(XML_c, XML_ext));
4016 pFS->endElement(FSNS(XML_c, XML_extLst));
4017 }
4018 pFS->endElement(FSNS(XML_c, XML_dLbls));
4019}
4020
4022 const uno::Reference< beans::XPropertySet > & xSeriesProperties,
4023 sal_Int32 nSeriesLength, sal_Int32 eChartType )
4024{
4025 uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
4026 bool bVaryColorsByPoint = false;
4027 Sequence< sal_Int32 > aDataPointSeq;
4028 if( xSeriesProperties.is())
4029 {
4030 Any aAny = xSeriesProperties->getPropertyValue( "AttributedDataPoints" );
4031 aAny >>= aDataPointSeq;
4032 xSeriesProperties->getPropertyValue( "VaryColorsByPoint" ) >>= bVaryColorsByPoint;
4033 }
4034
4035 const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
4036 sal_Int32 nElement;
4038 if( mxNewDiagram.is())
4039 xColorScheme.set( mxNewDiagram->getDefaultColorScheme());
4040
4041 if( bVaryColorsByPoint && xColorScheme.is() )
4042 {
4044 aAttrPointSet.reserve(aDataPointSeq.getLength());
4045 for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
4046 aAttrPointSet.insert(*p);
4047 const auto aEndIt = aAttrPointSet.end();
4048 for( nElement = 0; nElement < nSeriesLength; ++nElement )
4049 {
4050 uno::Reference< beans::XPropertySet > xPropSet;
4051 if( aAttrPointSet.find( nElement ) != aEndIt )
4052 {
4053 try
4054 {
4056 xSeries, nElement, getModel() );
4057 }
4058 catch( const uno::Exception & )
4059 {
4060 DBG_UNHANDLED_EXCEPTION( "oox", "Exception caught during Export of data point" );
4061 }
4062 }
4063 else
4064 {
4065 // property set only containing the color
4066 xPropSet.set( new ColorPropertySet( ColorTransparency, xColorScheme->getColorByIndex( nElement )));
4067 }
4068
4069 if( xPropSet.is() )
4070 {
4071 FSHelperPtr pFS = GetFS();
4072 pFS->startElement(FSNS(XML_c, XML_dPt));
4073 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nElement));
4074
4075 switch (eChartType)
4076 {
4077 case chart::TYPEID_PIE:
4079 {
4080 if( xPropSet.is() && GetProperty( xPropSet, "SegmentOffset") )
4081 {
4082 sal_Int32 nOffset = 0;
4083 mAny >>= nOffset;
4084 if (nOffset)
4085 pFS->singleElement( FSNS( XML_c, XML_explosion ),
4086 XML_val, OString::number( nOffset ) );
4087 }
4088 break;
4089 }
4090 default:
4091 break;
4092 }
4093 exportShapeProps( xPropSet );
4094
4095 pFS->endElement( FSNS( XML_c, XML_dPt ) );
4096 }
4097 }
4098 }
4099
4100 // Export Data Point Property in Charts even if the VaryColors is false
4101 if( bVaryColorsByPoint )
4102 return;
4103
4105 aAttrPointSet.reserve(aDataPointSeq.getLength());
4106 for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
4107 aAttrPointSet.insert(*p);
4108 const auto aEndIt = aAttrPointSet.end();
4109 for( nElement = 0; nElement < nSeriesLength; ++nElement )
4110 {
4111 uno::Reference< beans::XPropertySet > xPropSet;
4112 if( aAttrPointSet.find( nElement ) != aEndIt )
4113 {
4114 try
4115 {
4117 xSeries, nElement, getModel() );
4118 }
4119 catch( const uno::Exception & )
4120 {
4121 DBG_UNHANDLED_EXCEPTION( "oox", "Exception caught during Export of data point" );
4122 }
4123 }
4124
4125 if( xPropSet.is() )
4126 {
4127 FSHelperPtr pFS = GetFS();
4128 pFS->startElement(FSNS(XML_c, XML_dPt));
4129 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nElement));
4130
4131 switch( eChartType )
4132 {
4135 case chart::TYPEID_BAR:
4136 pFS->singleElement(FSNS(XML_c, XML_invertIfNegative), XML_val, "0");
4137 exportShapeProps(xPropSet);
4138 break;
4139
4140 case chart::TYPEID_LINE:
4143 exportMarker(xPropSet);
4144 break;
4145
4146 default:
4147 exportShapeProps(xPropSet);
4148 break;
4149 }
4150
4151 pFS->endElement( FSNS( XML_c, XML_dPt ) );
4152 }
4153 }
4154}
4155
4156void ChartExport::exportAxesId(bool bPrimaryAxes, bool bCheckCombinedAxes)
4157{
4158 sal_Int32 nAxisIdx, nAxisIdy;
4159 bool bPrimaryAxisExists = false;
4160 bool bSecondaryAxisExists = false;
4161 // let's check which axis already exists and which axis is attached to the actual dataseries
4162 if (maAxes.size() >= 2)
4163 {
4164 bPrimaryAxisExists = bPrimaryAxes && maAxes[1].nAxisType == AXIS_PRIMARY_Y;
4165 bSecondaryAxisExists = !bPrimaryAxes && maAxes[1].nAxisType == AXIS_SECONDARY_Y;
4166 }
4167 // tdf#114181 keep axes of combined charts
4168 if ( bCheckCombinedAxes && ( bPrimaryAxisExists || bSecondaryAxisExists ) )
4169 {
4170 nAxisIdx = maAxes[0].nAxisId;
4171 nAxisIdy = maAxes[1].nAxisId;
4172 }
4173 else
4174 {
4175 nAxisIdx = lcl_generateRandomValue();
4176 nAxisIdy = lcl_generateRandomValue();
4177 AxesType eXAxis = bPrimaryAxes ? AXIS_PRIMARY_X : AXIS_SECONDARY_X;
4178 AxesType eYAxis = bPrimaryAxes ? AXIS_PRIMARY_Y : AXIS_SECONDARY_Y;
4179 maAxes.emplace_back( eXAxis, nAxisIdx, nAxisIdy );
4180 maAxes.emplace_back( eYAxis, nAxisIdy, nAxisIdx );
4181 }
4182 FSHelperPtr pFS = GetFS();
4183 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdx));
4184 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdy));
4185 if (mbHasZAxis)
4186 {
4187 sal_Int32 nAxisIdz = 0;
4188 if( isDeep3dChart() )
4189 {
4190 nAxisIdz = lcl_generateRandomValue();
4191 maAxes.emplace_back( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy );
4192 }
4193 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdz));
4194 }
4195}
4196
4198{
4199 FSHelperPtr pFS = GetFS();
4200 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4201 // grouping
4202 if( GetProperty( xPropSet, "Stacked" ) )
4203 mAny >>= mbStacked;
4204 if( GetProperty( xPropSet, "Percent" ) )
4205 mAny >>= mbPercent;
4206
4207 const char* grouping = nullptr;
4208 if (mbStacked)
4209 grouping = "stacked";
4210 else if (mbPercent)
4211 grouping = "percentStacked";
4212 else
4213 {
4214 if( isBar && !isDeep3dChart() )
4215 {
4216 grouping = "clustered";
4217 }
4218 else
4219 grouping = "standard";
4220 }
4221 pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, grouping);
4222}
4223
4225{
4226 FSHelperPtr pFS = GetFS();
4227 Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, UNO_QUERY );
4228 if( !xRegressionCurveContainer.is() )
4229 return;
4230
4231 const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
4232 for( const Reference< chart2::XRegressionCurve >& xRegCurve : aRegCurveSeq )
4233 {
4234 if (!xRegCurve.is())
4235 continue;
4236
4237 Reference< XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
4238
4239 OUString aService;
4240 Reference< lang::XServiceName > xServiceName( xProperties, UNO_QUERY );
4241 if( !xServiceName.is() )
4242 continue;
4243
4244 aService = xServiceName->getServiceName();
4245
4246 if(aService != "com.sun.star.chart2.LinearRegressionCurve" &&
4247 aService != "com.sun.star.chart2.ExponentialRegressionCurve" &&
4248 aService != "com.sun.star.chart2.LogarithmicRegressionCurve" &&
4249 aService != "com.sun.star.chart2.PotentialRegressionCurve" &&
4250 aService != "com.sun.star.chart2.PolynomialRegressionCurve" &&
4251 aService != "com.sun.star.chart2.MovingAverageRegressionCurve")
4252 continue;
4253
4254 pFS->startElement(FSNS(XML_c, XML_trendline));
4255
4256 OUString aName;
4257 xProperties->getPropertyValue("CurveName") >>= aName;
4258 if(!aName.isEmpty())
4259 {
4260 pFS->startElement(FSNS(XML_c, XML_name));
4261 pFS->writeEscaped(aName);
4262 pFS->endElement( FSNS( XML_c, XML_name) );
4263 }
4264
4265 exportShapeProps( xProperties );
4266
4267 if( aService == "com.sun.star.chart2.LinearRegressionCurve" )
4268 {
4269 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "linear");
4270 }
4271 else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
4272 {
4273 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "exp");
4274 }
4275 else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
4276 {
4277 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "log");
4278 }
4279 else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
4280 {
4281 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "power");
4282 }
4283 else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
4284 {
4285 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "poly");
4286
4287 sal_Int32 aDegree = 2;
4288 xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
4289 pFS->singleElement(FSNS(XML_c, XML_order), XML_val, OString::number(aDegree));
4290 }
4291 else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
4292 {
4293 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "movingAvg");
4294
4295 sal_Int32 aPeriod = 2;
4296 xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
4297
4298 pFS->singleElement(FSNS(XML_c, XML_period), XML_val, OString::number(aPeriod));
4299 }
4300 else
4301 {
4302 // should never happen
4303 // This would produce invalid OOXML files so we check earlier for the type
4304 assert(false);
4305 }
4306
4307 double fExtrapolateForward = 0.0;
4308 double fExtrapolateBackward = 0.0;
4309
4310 xProperties->getPropertyValue("ExtrapolateForward") >>= fExtrapolateForward;
4311 xProperties->getPropertyValue("ExtrapolateBackward") >>= fExtrapolateBackward;
4312
4313 pFS->singleElement( FSNS( XML_c, XML_forward ),
4314 XML_val, OString::number(fExtrapolateForward) );
4315
4316 pFS->singleElement( FSNS( XML_c, XML_backward ),
4317 XML_val, OString::number(fExtrapolateBackward) );
4318
4319 bool bForceIntercept = false;
4320 xProperties->getPropertyValue("ForceIntercept") >>= bForceIntercept;
4321
4322 if (bForceIntercept)
4323 {
4324 double fInterceptValue = 0.0;
4325 xProperties->getPropertyValue("InterceptValue") >>= fInterceptValue;
4326
4327 pFS->singleElement( FSNS( XML_c, XML_intercept ),
4328 XML_val, OString::number(fInterceptValue) );
4329 }
4330
4331 // Equation properties
4332 Reference< XPropertySet > xEquationProperties( xRegCurve->getEquationProperties() );
4333
4334 // Show Equation
4335 bool bShowEquation = false;
4336 xEquationProperties->getPropertyValue("ShowEquation") >>= bShowEquation;
4337
4338 // Show R^2
4339 bool bShowCorrelationCoefficient = false;
4340 xEquationProperties->getPropertyValue("ShowCorrelationCoefficient") >>= bShowCorrelationCoefficient;
4341
4342 pFS->singleElement( FSNS( XML_c, XML_dispRSqr ),
4343 XML_val, ToPsz10(bShowCorrelationCoefficient) );
4344
4345 pFS->singleElement(FSNS(XML_c, XML_dispEq), XML_val, ToPsz10(bShowEquation));
4346
4347 pFS->endElement( FSNS( XML_c, XML_trendline ) );
4348 }
4349}
4350
4352{
4353 chart2::Symbol aSymbol;
4354 if( GetProperty( xPropSet, "Symbol" ) )
4355 mAny >>= aSymbol;
4356
4357 if(aSymbol.Style != chart2::SymbolStyle_STANDARD && aSymbol.Style != chart2::SymbolStyle_NONE)
4358 return;
4359
4360 FSHelperPtr pFS = GetFS();
4361 pFS->startElement(FSNS(XML_c, XML_marker));
4362
4363 sal_Int32 nSymbol = aSymbol.StandardSymbol;
4364 // TODO: more properties support for marker
4365 const char* pSymbolType; // no initialization here, to let compiler warn if we have a code path
4366 // where it stays uninitialized
4367 switch( nSymbol )
4368 {
4369 case 0:
4370 pSymbolType = "square";
4371 break;
4372 case 1:
4373 pSymbolType = "diamond";
4374 break;
4375 case 2:
4376 case 3:
4377 case 4:
4378 case 5:
4379 pSymbolType = "triangle";
4380 break;
4381 case 8:
4382 pSymbolType = "circle";
4383 break;
4384 case 9:
4385 pSymbolType = "star";
4386 break;
4387 case 10:
4388 pSymbolType = "x"; // in MS office 2010 built in symbol marker 'X' is represented as 'x'
4389 break;
4390 case 11:
4391 pSymbolType = "plus";
4392 break;
4393 case 13:
4394 pSymbolType = "dash";
4395 break;
4396 default:
4397 pSymbolType = "square";
4398 break;
4399 }
4400
4401 bool bSkipFormatting = false;
4402 if (aSymbol.Style == chart2::SymbolStyle_NONE)
4403 {
4404 bSkipFormatting = true;
4405 pSymbolType = "none";
4406 }
4407
4408 pFS->singleElement(FSNS(XML_c, XML_symbol), XML_val, pSymbolType);
4409
4410 if (!bSkipFormatting)
4411 {
4412 awt::Size aSymbolSize = aSymbol.Size;
4413 sal_Int32 nSize = std::max( aSymbolSize.Width, aSymbolSize.Height );
4414
4415 nSize = nSize/250.0*7.0 + 1; // just guessed based on some test cases,
4416 //the value is always 1 less than the actual value.
4417 nSize = std::clamp( int(nSize), 2, 72 );
4418 pFS->singleElement(FSNS(XML_c, XML_size), XML_val, OString::number(nSize));
4419
4420 pFS->startElement(FSNS(XML_c, XML_spPr));
4421
4422 util::Color aColor = aSymbol.FillColor;
4423 if (GetProperty(xPropSet, "Color"))
4424 mAny >>= aColor;
4425
4426 if (aColor == -1)
4427 {
4428 pFS->singleElement(FSNS(XML_a, XML_noFill));
4429 }
4430 else
4432
4433 pFS->endElement( FSNS( XML_c, XML_spPr ) );
4434 }
4435
4436 pFS->endElement( FSNS( XML_c, XML_marker ) );
4437}
4438
4440{
4441 FSHelperPtr pFS = GetFS();
4442 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY );
4443 sal_Int32 nSplineType = 0;
4444 if( GetProperty( xPropSet, "SplineType" ) )
4445 mAny >>= nSplineType;
4446 const char* pVal = nSplineType != 0 ? "1" : "0";
4447 pFS->singleElement(FSNS(XML_c, XML_smooth), XML_val, pVal);
4448}
4449
4451{
4452 FSHelperPtr pFS = GetFS();
4453 sal_Int32 nStartingAngle = 0;
4454 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4455 if( GetProperty( xPropSet, "StartingAngle" ) )
4456 mAny >>= nStartingAngle;
4457
4458 // convert to ooxml angle
4459 nStartingAngle = (450 - nStartingAngle ) % 360;
4460 pFS->singleElement(FSNS(XML_c, XML_firstSliceAng), XML_val, OString::number(nStartingAngle));
4461}
4462
4463namespace {
4464
4465const char* getErrorBarStyle(sal_Int32 nErrorBarStyle)
4466{
4467 switch(nErrorBarStyle)
4468 {
4469 case cssc::ErrorBarStyle::NONE:
4470 return nullptr;
4471 case cssc::ErrorBarStyle::VARIANCE:
4472 break;
4473 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
4474 return "stdDev";
4475 case cssc::ErrorBarStyle::ABSOLUTE:
4476 return "fixedVal";
4477 case cssc::ErrorBarStyle::RELATIVE:
4478 return "percentage";
4479 case cssc::ErrorBarStyle::ERROR_MARGIN:
4480 break;
4481 case cssc::ErrorBarStyle::STANDARD_ERROR:
4482 return "stdErr";
4483 case cssc::ErrorBarStyle::FROM_DATA:
4484 return "cust";
4485 default:
4486 assert(false && "can't happen");
4487 }
4488 return nullptr;
4489}
4490
4491Reference< chart2::data::XDataSequence> getLabeledSequence(
4492 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences,
4493 bool bPositive )
4494{
4495 OUString aDirection;
4496 if(bPositive)
4497 aDirection = "positive";
4498 else
4499 aDirection = "negative";
4500
4501 for( const auto& rSequence : aSequences )
4502 {
4503 if( rSequence.is())
4504 {
4505 uno::Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues());
4506 uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
4507 OUString aRole;
4508 if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) &&
4509 aRole.match( "error-bars" ) && aRole.indexOf(aDirection) >= 0 )
4510 {
4511 return xSequence;
4512 }
4513 }
4514 }
4515
4516 return Reference< chart2::data::XDataSequence > ();
4517}
4518
4519}
4520
4521void ChartExport::exportErrorBar(const Reference< XPropertySet>& xErrorBarProps, bool bYError)
4522{
4523 sal_Int32 nErrorBarStyle = cssc::ErrorBarStyle::NONE;
4524 xErrorBarProps->getPropertyValue("ErrorBarStyle") >>= nErrorBarStyle;
4525 const char* pErrorBarStyle = getErrorBarStyle(nErrorBarStyle);
4526 if(!pErrorBarStyle)
4527 return;
4528
4529 FSHelperPtr pFS = GetFS();
4530 pFS->startElement(FSNS(XML_c, XML_errBars));
4531 pFS->singleElement(FSNS(XML_c, XML_errDir), XML_val, bYError ? "y" : "x");
4532 bool bPositive = false, bNegative = false;
4533 xErrorBarProps->getPropertyValue("ShowPositiveError") >>= bPositive;
4534 xErrorBarProps->getPropertyValue("ShowNegativeError") >>= bNegative;
4535 const char* pErrBarType;
4536 if(bPositive && bNegative)
4537 pErrBarType = "both";
4538 else if(bPositive)
4539 pErrBarType = "plus";
4540 else if(bNegative)
4541 pErrBarType = "minus";
4542 else
4543 {
4544 // what the hell should we do now?
4545 // at least this makes the file valid
4546 pErrBarType = "both";
4547 }
4548 pFS->singleElement(FSNS(XML_c, XML_errBarType), XML_val, pErrBarType);
4549 pFS->singleElement(FSNS(XML_c, XML_errValType), XML_val, pErrorBarStyle);
4550 pFS->singleElement(FSNS(XML_c, XML_noEndCap), XML_val, "0");
4551 if(nErrorBarStyle == cssc::ErrorBarStyle::FROM_DATA)
4552 {
4553 uno::Reference< chart2::data::XDataSource > xDataSource(xErrorBarProps, uno::UNO_QUERY);
4555 xDataSource->getDataSequences();
4556
4557 if(bPositive)
4558 {
4559 exportSeriesValues(getLabeledSequence(aSequences, true), XML_plus);
4560 }
4561
4562 if(bNegative)
4563 {
4564 exportSeriesValues(getLabeledSequence(aSequences, false), XML_minus);
4565 }
4566 }
4567 else
4568 {
4569 double nVal = 0.0;
4570 if(nErrorBarStyle == cssc::ErrorBarStyle::STANDARD_DEVIATION)
4571 {
4572 xErrorBarProps->getPropertyValue("Weight") >>= nVal;
4573 }
4574 else
4575 {
4576 if(bPositive)
4577 xErrorBarProps->getPropertyValue("PositiveError") >>= nVal;
4578 else
4579 xErrorBarProps->getPropertyValue("NegativeError") >>= nVal;
4580 }
4581
4582 pFS->singleElement(FSNS(XML_c, XML_val), XML_val, OString::number(nVal));
4583 }
4584
4585 exportShapeProps( xErrorBarProps );
4586
4587 pFS->endElement( FSNS( XML_c, XML_errBars) );
4588}
4589
4591{
4592 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4593 if( !xPropSet.is() )
4594 return;
4595 FSHelperPtr pFS = GetFS();
4596 pFS->startElement(FSNS(XML_c, XML_view3D));
4597 sal_Int32 eChartType = getChartType( );
4598 // rotX
4599 if( GetProperty( xPropSet, "RotationHorizontal" ) )
4600 {
4601 sal_Int32 nRotationX = 0;
4602 mAny >>= nRotationX;
4603 if( nRotationX < 0 )
4604 {
4605 if(eChartType == chart::TYPEID_PIE)
4606 {
4607 /* In OOXML we get value in 0..90 range for pie chart X rotation , whereas we expect it to be in -90..90 range,
4608 so we convert that during import. It is modified in View3DConverter::convertFromModel()
4609 here we convert it back to 0..90 as we received in import */
4610 nRotationX += 90; // X rotation (map Chart2 [-179,180] to OOXML [0..90])
4611 }
4612 else
4613 nRotationX += 360; // X rotation (map Chart2 [-179,180] to OOXML [-90..90])
4614 }
4615 pFS->singleElement(FSNS(XML_c, XML_rotX), XML_val, OString::number(nRotationX));
4616 }
4617 // rotY
4618 if( GetProperty( xPropSet, "RotationVertical" ) )
4619 {
4620 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
4621 if( eChartType == chart::TYPEID_PIE && GetProperty( xPropSet, "StartingAngle" ) )
4622 {
4623 // Y rotation used as 'first pie slice angle' in 3D pie charts
4624 sal_Int32 nStartingAngle=0;
4625 mAny >>= nStartingAngle;
4626 // convert to ooxml angle
4627 nStartingAngle = (450 - nStartingAngle ) % 360;
4628 pFS->singleElement(FSNS(XML_c, XML_rotY), XML_val, OString::number(nStartingAngle));
4629 }
4630 else
4631 {
4632 sal_Int32 nRotationY = 0;
4633 mAny >>= nRotationY;
4634 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
4635 if( nRotationY < 0 )
4636 nRotationY += 360;
4637 pFS->singleElement(FSNS(XML_c, XML_rotY), XML_val, OString::number(nRotationY));
4638 }
4639 }
4640 // rAngAx
4641 if( GetProperty( xPropSet, "RightAngledAxes" ) )
4642 {
4643 bool bRightAngled = false;
4644 mAny >>= bRightAngled;
4645 const char* sRightAngled = bRightAngled ? "1":"0";
4646 pFS->singleElement(FSNS(XML_c, XML_rAngAx), XML_val, sRightAngled);
4647 }
4648 // perspective
4649 if( GetProperty( xPropSet, "Perspective" ) )
4650 {
4651 sal_Int32 nPerspective = 0;
4652 mAny >>= nPerspective;
4653 // map Chart2 [0,100] to OOXML [0..200]
4654 nPerspective *= 2;
4655 pFS->singleElement(FSNS(XML_c, XML_perspective), XML_val, OString::number(nPerspective));
4656 }
4657 pFS->endElement( FSNS( XML_c, XML_view3D ) );
4658}
4659
4661{
4662 bool isDeep = false;
4663 if( mbIs3DChart )
4664 {
4665 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4666 if( GetProperty( xPropSet, "Deep" ) )
4667 mAny >>= isDeep;
4668 }
4669 return isDeep;
4670}
4671
4672OUString ChartExport::getNumberFormatCode(sal_Int32 nKey) const
4673{
4674 /* XXX if this was called more than one or two times per export the two
4675 * SvNumberFormatter instances and NfKeywordTable should be member
4676 * variables and initialized only once. */
4677
4678 OUString aCode("General"); // init with fallback
4679 uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(mxChartModel, uno::UNO_QUERY_THROW);
4680 SvNumberFormatsSupplierObj* pSupplierObj = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xNumberFormatsSupplier);
4681 if (!pSupplierObj)
4682 return aCode;
4683
4684 SvNumberFormatter* pNumberFormatter = pSupplierObj->GetNumberFormatter();
4685 if (!pNumberFormatter)
4686 return aCode;
4687
4689 NfKeywordTable aKeywords;
4690 aTempFormatter.FillKeywordTableForExcel( aKeywords);
4691 aCode = pNumberFormatter->GetFormatStringForExcel( nKey, aKeywords, aTempFormatter);
4692
4693 return aCode;
4694}
4695
4696}// oox
4697
4698/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool mbExport
sal_Int32 meDefault
std::unordered_set< sal_Int32 > maAllowedValues
OUString m_aRole
sal_uInt8 GetRed() const
static css::uno::Reference< css::beans::XPropertySet > createOldAPIDataPointPropertySet(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, sal_Int32 nPointIndex, const css::uno::Reference< css::frame::XModel > &xChartModel)
static css::uno::Reference< css::beans::XPropertySet > createOldAPISeriesPropertySet(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, const css::uno::Reference< css::frame::XModel > &xChartModel)
SvNumberFormatter * GetNumberFormatter() const
OUString GetFormatStringForExcel(sal_uInt32 nKey, const NfKeywordTable &rKeywords, SvNumberFormatter &rTempFormatter) const
void FillKeywordTableForExcel(NfKeywordTable &rKeywords)
void reserve(size_type amount)
const_iterator find(const Value &x) const
const_iterator end() const
std::pair< const_iterator, bool > insert(Value &&x)
A wrapper for a UNO property set.
Definition: propertyset.hxx:58
bool getBoolProperty(sal_Int32 nPropId) const
Gets the specified boolean property from the property set.
Definition: propertyset.hxx:99
bool getProperty(Type &orValue, sal_Int32 nPropId) const
Gets the specified property from the property set.
Definition: propertyset.hxx:94
const css::uno::Reference< css::lang::XMultiServiceFactory > & getModelFactory() const
Returns the service factory provided by the document model (always existing).
Definition: filterbase.cxx:225
OUString addRelation(const OUString &rType, std::u16string_view rTarget)
Adds new relation.
OUString getNamespaceURL(sal_Int32 nNSID) const
const css::uno::Reference< css::frame::XModel > & getModel() const
void _exportAxis(const css::uno::Reference< css::beans::XPropertySet > &xAxisProp, const css::uno::Reference< css::drawing::XShape > &xAxisTitle, const css::uno::Reference< css::beans::XPropertySet > &xMajorGrid, const css::uno::Reference< css::beans::XPropertySet > &xMinorGrid, sal_Int32 nAxisType, const char *sAxisPos, const AxisIdPair &rAxisIdPair)
void exportAdditionalShapes(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void exportVaryColors(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportAllSeries(const css::uno::Reference< css::chart2::XChartType > &xChartType, bool &rPrimaryAxes)
void exportScatterChartSeries(const css::uno::Reference< css::chart2::XChartType > &xChartType, const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > *pSeries)
void exportPlotArea(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void exportShapeProps(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
css::uno::Reference< css::chart2::XDiagram > mxNewDiagram
void exportExternalData(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void exportBitmapFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportSeries(const css::uno::Reference< css::chart2::XChartType > &xChartType, const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > &rSeriesSeq, bool &rPrimaryAxes)
void exportRadarChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportAxesId(bool bPrimaryAxes, bool bCheckCombinedAxes=false)
void exportMissingValueTreatment(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportLegend(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void InitRangeSegmentationProperties(const css::uno::Reference< css::chart2::XChartDocument > &xChartDoc)
void exportMarker(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
css::uno::Reference< css::chart2::data::XDataSequence > mxCategoriesValues
void exportHatch(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportDoughnutChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
css::uno::Reference< css::chart::XDiagram > mxDiagram
void exportAreaChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportTrendlines(const css::uno::Reference< css::chart2::XDataSeries > &xSeries)
void exportSolidFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportBubbleChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportManualLayout(const css::chart2::RelativePosition &rPos, const css::chart2::RelativeSize &rSize, const bool bIsExcludingDiagramPositioning)
void exportDataLabels(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, sal_Int32 nSeriesLength, sal_Int32 eChartType, DataLabelsRange &rDLblsRange)
std::set< sal_Int32 > maExportedAxis
void exportTitle(const css::uno::Reference< css::drawing::XShape > &xShape, const OUString *pSubText=nullptr)
void exportScatterChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportSurfaceChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportChart(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
OUString parseFormula(const OUString &rRange)
void SetURLTranslator(const std::shared_ptr< URLTransformer > &pTransformer)
void exportChartSpace(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc, bool bIncludeTable)
css::uno::Sequence< css::uno::Sequence< rtl::OUString > > getSplitCategoriesList(const OUString &rRange)
void exportSeriesCategory(const css::uno::Reference< css::chart2::data::XDataSequence > &xValueSeq, sal_Int32 nValueType=XML_cat)
void exportPieChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportSeriesText(const css::uno::Reference< css::chart2::data::XDataSequence > &xValueSeq)
void exportDataPoints(const css::uno::Reference< css::beans::XPropertySet > &xSeriesProperties, sal_Int32 nSeriesLength, sal_Int32 eChartType)
void exportCandleStickSeries(const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > &aSeriesSeq, bool &rPrimaryAxes)
void exportFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportGrouping(bool isBar=false)
css::uno::Reference< css::frame::XModel > mxChartModel
ChartExport(sal_Int32 nXmlNamespace, ::sax_fastparser::FSHelperPtr pFS, css::uno::Reference< css::frame::XModel > const &xModel, ::oox::core::XmlFilterBase *pFB, DocumentType eDocumentType)
OUString getNumberFormatCode(sal_Int32 nKey) const
void exportErrorBar(const css::uno::Reference< css::beans::XPropertySet > &xErrorBarProps, bool bYError)
void exportTextProps(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportGradientFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportLineChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportUpDownBars(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportStockChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
std::shared_ptr< URLTransformer > mpURLTransformer
void exportSeriesValues(const css::uno::Reference< css::chart2::data::XDataSequence > &xValueSeq, sal_Int32 nValueType=XML_val)
void WriteChartObj(const css::uno::Reference< css::drawing::XShape > &xShape, sal_Int32 nID, sal_Int32 nChartCount)
void exportBarChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportAxis(const AxisIdPair &rAxisIdPair)
A helper container class to collect the chart data point labels and the address of the cell[range] fr...
const OUString & getRange() const
Returns the address of the cell[range] from which label contents are sourced.
void setRange(const OUString &rRange)
Sets the address of the cell[range] from which label contents are sourced.
bool empty() const
Returns whether the container is empty or not.
void setLabel(sal_Int32 nIndex, const OUString &rText)
Adds a new indexed label text.
LabelsRangeMap::const_iterator begin() const
size_t count() const
Returns the count of labels stored.
bool hasLabel(sal_Int32 nIndex) const
Indicates whether the container has a label with index specified by nIndex.
LabelsRangeMap::const_iterator end() const
static sal_Int32 getNewDrawingUniqueId()
Definition: drawingml.hxx:356
::oox::core::XmlFilterBase * mpFB
Definition: drawingml.hxx:162
void WriteGradientFill(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
static void WriteFromTo(const css::uno::Reference< css::drawing::XShape > &rXShape, const css::awt::Size &aPageSize, const sax_fastparser::FSHelperPtr &pDrawing)
Definition: drawingml.cxx:6142
::sax_fastparser::FSHelperPtr mpFS
Definition: drawingml.hxx:161
bool GetProperty(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &aName)
Definition: drawingml.cxx:295
void SetFS(::sax_fastparser::FSHelperPtr pFS)
Definition: drawingml.hxx:218
const ::sax_fastparser::FSHelperPtr & GetFS() const
Definition: drawingml.hxx:219
::oox::core::XmlFilterBase * GetFB()
Definition: drawingml.hxx:220
DocumentType GetDocumentType() const
Definition: drawingml.hxx:221
void WriteShapeTransformation(const css::uno::Reference< css::drawing::XShape > &rXShape, sal_Int32 nXmlNamespace, bool bFlipH=false, bool bFlipV=false, bool bSuppressRotation=false, bool bSuppressFlipping=false, bool bFlippedBeforeRotation=false)
Definition: drawingml.cxx:1972
void WriteSolidFill(::Color nColor, sal_Int32 nAlpha=MAX_PERCENT)
Definition: drawingml.cxx:435
void WritePattFill(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
sax_fastparser::FSHelperPtr CreateOutputStream(const OUString &sFullStream, std::u16string_view sRelativeStream, const css::uno::Reference< css::io::XOutputStream > &xParentRelation, const char *sContentType, const char *sRelationshipType, OUString *pRelationshipId)
Definition: drawingml.cxx:4983
void WriteOutline(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, css::uno::Reference< css::frame::XModel > const &xModel=nullptr)
Definition: drawingml.cxx:897
void WriteXGraphicBlipFill(css::uno::Reference< css::beans::XPropertySet > const &rXPropSet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic, sal_Int32 nXmlNamespace, bool bWriteMode, bool bRelPathToMedia=false)
Definition: drawingml.cxx:1632
void WriteRunProperties(const css::uno::Reference< css::beans::XPropertySet > &rRun, bool bIsField, sal_Int32 nElement, bool bCheckDirect, bool &rbOverridingCharHeight, sal_Int32 &rnCharHeight, sal_Int16 nScriptType=css::i18n::ScriptType::LATIN, const css::uno::Reference< css::beans::XPropertySet > &rXShapePropSet={})
Definition: drawingml.cxx:2098
ShapeExport & WriteShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Write the DrawingML for a particular shape.
Definition: shapes.cxx:1995
ColorTransparency
#define TOOLS_WARN_EXCEPTION(area, stream)
#define TOOLS_INFO_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
OString sName
Definition: drawingml.cxx:4170
float u
float y
float x
sal_Int16 nValue
constexpr sal_Int32 FSNS(sal_Int32 namespc, sal_Int32 element)
const sal_uInt16 idx[]
Sequence< PropertyValue > aArguments
sal_Int32 nIndex
OUString aName
void * p
uno_Any a
#define LANGUAGE_ENGLISH_US
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
aStr
double getLength(const B2DPolygon &rCandidate)
@ Exception
enum SAL_DLLPUBLIC_RTTI FillStyle
int uniform_int_distribution(int a, int b)
Reference< XComponentContext > getProcessComponentContext()
std::shared_ptr< T > make_shared(Args &&... args)
constexpr T & temporary(T &&x)
const TypeGroupInfo & GetTypeGroupInfo(TypeId eType)
TypeId
Enumerates different chart types.
@ TYPEID_OFPIE
Doughnut (ring) chart.
@ TYPEID_LINE
Horizontal bar chart.
@ TYPEID_HORBAR
Vertical bar chart.
@ TYPEID_PIE
Filled radar chart.
@ TYPEID_UNKNOWN
Surface chart.
@ TYPEID_BUBBLE
Scatter (XY) chart.
@ TYPEID_RADARAREA
Linear radar chart.
@ TYPEID_SCATTER
Pie-to-pie or pie-to-bar chart.
static bool lcl_isSeriesAttachedToFirstAxis(const Reference< chart2::XDataSeries > &xDataSeries)
static OUString lcl_flattenStringSequence(const Sequence< OUString > &rSequence)
static sal_Int32 lcl_getAlphaFromTransparenceGradient(const awt::Gradient &rGradient, bool bStart)
OString calcRotationValue(sal_Int32 nRotation)
nRotation is a 100th of a degree and the return value is in a 60,000th of a degree
static ::std::vector< double > lcl_getAllValuesFromSequence(const Reference< chart2::data::XDataSequence > &xSeq)
static Sequence< OUString > lcl_getLabelSequence(const Reference< chart2::data::XDataSequence > &xLabelSeq)
static sal_Int32 lcl_getCategoryAxisType(const Reference< chart2::XDiagram > &xDiagram, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex)
static sal_Int32 lcl_getChartType(std::u16string_view sChartType)
static bool lcl_isCategoryAxisShifted(const Reference< chart2::XDiagram > &xDiagram)
static void lcl_fillCategoriesIntoStringVector(const Reference< chart2::data::XDataSequence > &xCategories, ::std::vector< OUString > &rOutCategories)
static Reference< chart2::data::XLabeledDataSequence > lcl_getCategories(const Reference< chart2::XDiagram > &xDiagram, bool &bHasDateCategories)
static cssc::TimeIncrement lcl_getDateTimeIncrement(const Reference< chart2::XDiagram > &xDiagram, sal_Int32 nAxisIndex)
static bool lcl_hasCategoryLabels(const Reference< chart2::XChartDocument > &xChartDoc)
static OUString lclGetTimeUnitToken(sal_Int32 nTimeUnit)
const sal_Int32 MAX_PERCENT
static Reference< chart2::data::XLabeledDataSequence > lcl_getDataSequenceByRole(const Sequence< Reference< chart2::data::XLabeledDataSequence > > &aLabeledSeq, const OUString &rRole)
const sal_Int32 PER_PERCENT
static sal_Int32 lcl_generateRandomValue()
sal_Int64 convertHmmToEmu(sal_Int32 nValue)
Converts the passed 32-bit integer value from 1/100 mm to EMUs.
OUString getRelationship(Relationship eRelationship)
end
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
orientation
std::shared_ptr< FastSerializerHelper > FSHelperPtr
bool getOutputStream(ProgramOptions const &options, OString const &extension, std::ostream **ppOutputStream, OString &targetSourceFileName, OString &tmpSourceFileName)
sal_Int32 h
sal_Int32 w
::std::array< OUString, NF_KEYWORD_ENTRIES_COUNT > NfKeywordTable
std::unique_ptr< uint8_t[]> pLabels
Contains info for a chart type related to the OpenOffice.org chart module.
sal_Int32 mnDefLabelPos
Mode for varying point colors.
bool hasValue()
Reference< XModel > xModel
bool bVisible
css::drawing::Direction3D aDirection
unsigned char sal_uInt8
ResultType type
OUString aLabel
OUString sId
static constexpr const char * ToPsz10(bool b)
Definition: utils.hxx:51
sal_Int32 nLength