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}
878
880{
881 if( !xChartDoc.is())
882 return;
883
884 try
885 {
886 Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
887 OSL_ENSURE( xDataProvider.is(), "No DataProvider" );
888 if( xDataProvider.is())
889 {
891 }
892 }
893 catch( const uno::Exception & )
894 {
896 }
897}
898
900{
901 Reference< chart2::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
902 OSL_ASSERT( xChartDoc.is() );
903 if( !xChartDoc.is() )
904 return;
906 // TODO: export chart
908}
909
911{
912 Reference< css::chart::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
913 if( xChartDoc.is())
914 {
915 // determine if data comes from the outside
916 bool bIncludeTable = true;
917
918 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
919 if( xNewDoc.is())
920 {
921 // check if we have own data. If so we must not export the complete
922 // range string, as this is our only indicator for having own or
923 // external data. @todo: fix this in the file format!
924 Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
925 if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
926 {
927 bIncludeTable = false;
928 }
929 }
930 exportChartSpace( xChartDoc, bIncludeTable );
931 }
932 else
933 {
934 OSL_FAIL( "Couldn't export chart due to wrong XModel" );
935 }
936}
937
939 bool bIncludeTable )
940{
941 FSHelperPtr pFS = GetFS();
942 XmlFilterBase* pFB = GetFB();
943 pFS->startElement( FSNS( XML_c, XML_chartSpace ),
944 FSNS( XML_xmlns, XML_c ), pFB->getNamespaceURL(OOX_NS(dmlChart)),
945 FSNS( XML_xmlns, XML_a ), pFB->getNamespaceURL(OOX_NS(dml)),
946 FSNS( XML_xmlns, XML_r ), pFB->getNamespaceURL(OOX_NS(officeRel)));
947 // TODO: get the correct editing language
948 pFS->singleElement(FSNS(XML_c, XML_lang), XML_val, "en-US");
949
950 pFS->singleElement(FSNS(XML_c, XML_roundedCorners), XML_val, "0");
951
952 if( !bIncludeTable )
953 {
954 // TODO:external data
955 }
956 //XML_chart
957 exportChart(xChartDoc);
958
959 // TODO: printSettings
960 // TODO: style
961 // TODO: text properties
962 // TODO: shape properties
963 Reference< XPropertySet > xPropSet = xChartDoc->getArea();
964 if( xPropSet.is() )
965 exportShapeProps( xPropSet );
966
967 //XML_externalData
968 exportExternalData(xChartDoc);
969
970 // export additional shapes in chart
971 exportAdditionalShapes(xChartDoc);
972
973 pFS->endElement( FSNS( XML_c, XML_chartSpace ) );
974}
975
977{
978 // Embedded external data is grab bagged for docx file hence adding export part of
979 // external data for docx files only.
981 return;
982
983 OUString externalDataPath;
984 Reference< beans::XPropertySet > xDocPropSet( xChartDoc->getDiagram(), uno::UNO_QUERY );
985 if( xDocPropSet.is())
986 {
987 try
988 {
989 Any aAny( xDocPropSet->getPropertyValue( "ExternalData" ));
990 aAny >>= externalDataPath;
991 }
992 catch( beans::UnknownPropertyException & )
993 {
994 SAL_WARN("oox", "Required property not found in ChartDocument");
995 }
996 }
997 if(externalDataPath.isEmpty())
998 return;
999
1000 // Here adding external data entry to relationship.
1001 OUString relationPath = externalDataPath;
1002 // Converting absolute path to relative path.
1003 if( externalDataPath[ 0 ] != '.' && externalDataPath[ 1 ] != '.')
1004 {
1005 sal_Int32 nSepPos = externalDataPath.indexOf( '/', 0 );
1006 if( nSepPos > 0)
1007 {
1008 relationPath = relationPath.copy( nSepPos, ::std::max< sal_Int32 >( externalDataPath.getLength(), 0 ) - nSepPos );
1009 relationPath = ".." + relationPath;
1010 }
1011 }
1012 FSHelperPtr pFS = GetFS();
1014 if (relationPath.endsWith(".bin"))
1016
1017 OUString sRelId = GetFB()->addRelation(pFS->getOutputStream(),
1018 type,
1019 relationPath);
1020 pFS->singleElementNS(XML_c, XML_externalData, FSNS(XML_r, XML_id), sRelId);
1021}
1022
1024{
1025 Reference< beans::XPropertySet > xDocPropSet(xChartDoc, uno::UNO_QUERY);
1026 if (!xDocPropSet.is())
1027 return;
1028
1029 css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes;
1030 // get a sequence of non-chart shapes
1031 try
1032 {
1033 Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes");
1034 if( (aShapesAny >>= mxAdditionalShapes) && mxAdditionalShapes.is() )
1035 {
1036 OUString sId;
1037 const char* sFullPath = nullptr;
1038 const char* sRelativePath = nullptr;
1039 sal_Int32 nDrawing = getNewDrawingUniqueId();
1040
1041 switch (GetDocumentType())
1042 {
1043 case DOCUMENT_DOCX:
1044 {
1045 sFullPath = "word/drawings/drawing";
1046 sRelativePath = "../drawings/drawing";
1047 break;
1048 }
1049 case DOCUMENT_PPTX:
1050 {
1051 sFullPath = "ppt/drawings/drawing";
1052 sRelativePath = "../drawings/drawing";
1053 break;
1054 }
1055 case DOCUMENT_XLSX:
1056 {
1057 sFullPath = "xl/drawings/drawing";
1058 sRelativePath = "../drawings/drawing";
1059 break;
1060 }
1061 default:
1062 {
1063 sFullPath = "drawings/drawing";
1064 sRelativePath = "drawings/drawing";
1065 break;
1066 }
1067 }
1068 OUString sFullStream = OUStringBuffer()
1069 .appendAscii(sFullPath)
1070 .append(OUString::number(nDrawing) + ".xml")
1071 .makeStringAndClear();
1072 OUString sRelativeStream = OUStringBuffer()
1073 .appendAscii(sRelativePath)
1074 .append(OUString::number(nDrawing) + ".xml")
1075 .makeStringAndClear();
1076
1078 sFullStream,
1079 sRelativeStream,
1081 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml",
1083 &sId);
1084
1085 GetFS()->singleElementNS(XML_c, XML_userShapes, FSNS(XML_r, XML_id), sId);
1086
1087 XmlFilterBase* pFB = GetFB();
1088 pDrawing->startElement(FSNS(XML_c, XML_userShapes),
1089 FSNS(XML_xmlns, XML_cdr), pFB->getNamespaceURL(OOX_NS(dmlChartDr)),
1090 FSNS(XML_xmlns, XML_a), pFB->getNamespaceURL(OOX_NS(dml)),
1091 FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart)),
1092 FSNS(XML_xmlns, XML_r), pFB->getNamespaceURL(OOX_NS(officeRel)));
1093
1094 const sal_Int32 nShapeCount(mxAdditionalShapes->getCount());
1095 for (sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
1096 {
1098 mxAdditionalShapes->getByIndex(nShapeId) >>= xShape;
1099 SAL_WARN_IF(!xShape.is(), "xmloff.chart", "Shape without an XShape?");
1100 if (!xShape.is())
1101 continue;
1102
1103 // TODO: absSizeAnchor: we import both (absSizeAnchor and relSizeAnchor), but there is no essential difference between them.
1104 pDrawing->startElement(FSNS(XML_cdr, XML_relSizeAnchor));
1105 uno::Reference< beans::XPropertySet > xShapeProperties(xShape, uno::UNO_QUERY);
1106 if( xShapeProperties.is() )
1107 {
1108 Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1109 awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1110 WriteFromTo( xShape, aPageSize, pDrawing );
1111
1112 ShapeExport aExport(XML_cdr, pDrawing, nullptr, GetFB(), GetDocumentType(), nullptr, true);
1113 aExport.WriteShape(xShape);
1114 }
1115 pDrawing->endElement(FSNS(XML_cdr, XML_relSizeAnchor));
1116 }
1117 pDrawing->endElement(FSNS(XML_c, XML_userShapes));
1118 }
1119 }
1120 catch (const uno::Exception&)
1121 {
1122 TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found");
1123 }
1124}
1125
1127{
1128 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
1129 mxDiagram.set( xChartDoc->getDiagram() );
1130 if( xNewDoc.is())
1131 mxNewDiagram.set( xNewDoc->getFirstDiagram());
1132
1133 // get Properties of ChartDocument
1134 bool bHasMainTitle = false;
1135 OUString aSubTitle;
1136 bool bHasLegend = false;
1137 Reference< beans::XPropertySet > xDocPropSet( xChartDoc, uno::UNO_QUERY );
1138 if( xDocPropSet.is())
1139 {
1140 try
1141 {
1142 Any aAny( xDocPropSet->getPropertyValue("HasMainTitle"));
1143 aAny >>= bHasMainTitle;
1144 aAny = xDocPropSet->getPropertyValue("HasLegend");
1145 aAny >>= bHasLegend;
1146 }
1147 catch( beans::UnknownPropertyException & )
1148 {
1149 SAL_WARN("oox", "Required property not found in ChartDocument");
1150 }
1151 } // if( xDocPropSet.is())
1152
1153 Reference< beans::XPropertySet > xPropSubTitle( xChartDoc->getSubTitle(), UNO_QUERY );
1154 if( xPropSubTitle.is())
1155 {
1156 try
1157 {
1158 xPropSubTitle->getPropertyValue("String") >>= aSubTitle;
1159 }
1160 catch( beans::UnknownPropertyException & )
1161 {
1162 }
1163 }
1164
1165 // chart element
1166 FSHelperPtr pFS = GetFS();
1167 pFS->startElement(FSNS(XML_c, XML_chart));
1168
1169 // titles
1170 if( bHasMainTitle )
1171 {
1172 exportTitle( xChartDoc->getTitle(), !aSubTitle.isEmpty() ? &aSubTitle : nullptr );
1173 pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0");
1174 }
1175 else if( !aSubTitle.isEmpty() )
1176 {
1177 exportTitle( xChartDoc->getSubTitle(), nullptr );
1178 pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0");
1179 }
1180 else
1181 {
1182 pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "1");
1183 }
1184
1185 InitPlotArea( );
1186 if( mbIs3DChart )
1187 {
1188 exportView3D();
1189
1190 // floor
1192 if( xFloor.is() )
1193 {
1194 pFS->startElement(FSNS(XML_c, XML_floor));
1195 exportShapeProps( xFloor );
1196 pFS->endElement( FSNS( XML_c, XML_floor ) );
1197 }
1198
1199 // LibreOffice doesn't distinguish between sideWall and backWall (both are using the same color).
1200 // It is controlled by the same Wall property.
1202 if( xWall.is() )
1203 {
1204 // sideWall
1205 pFS->startElement(FSNS(XML_c, XML_sideWall));
1206 exportShapeProps( xWall );
1207 pFS->endElement( FSNS( XML_c, XML_sideWall ) );
1208
1209 // backWall
1210 pFS->startElement(FSNS(XML_c, XML_backWall));
1211 exportShapeProps( xWall );
1212 pFS->endElement( FSNS( XML_c, XML_backWall ) );
1213 }
1214
1215 }
1216 // plot area
1217 exportPlotArea( xChartDoc );
1218 // legend
1219 if( bHasLegend )
1220 exportLegend( xChartDoc );
1221
1222 uno::Reference<beans::XPropertySet> xDiagramPropSet(xChartDoc->getDiagram(), uno::UNO_QUERY);
1223 uno::Any aPlotVisOnly = xDiagramPropSet->getPropertyValue("IncludeHiddenCells");
1224 bool bIncludeHiddenCells = false;
1225 aPlotVisOnly >>= bIncludeHiddenCells;
1226 pFS->singleElement(FSNS(XML_c, XML_plotVisOnly), XML_val, ToPsz10(!bIncludeHiddenCells));
1227
1229
1230 pFS->endElement( FSNS( XML_c, XML_chart ) );
1231}
1232
1233void ChartExport::exportMissingValueTreatment(const uno::Reference<beans::XPropertySet>& xPropSet)
1234{
1235 if (!xPropSet.is())
1236 return;
1237
1238 sal_Int32 nVal = 0;
1239 uno::Any aAny = xPropSet->getPropertyValue("MissingValueTreatment");
1240 if (!(aAny >>= nVal))
1241 return;
1242
1243 const char* pVal = nullptr;
1244 switch (nVal)
1245 {
1246 case cssc::MissingValueTreatment::LEAVE_GAP:
1247 pVal = "gap";
1248 break;
1249 case cssc::MissingValueTreatment::USE_ZERO:
1250 pVal = "zero";
1251 break;
1252 case cssc::MissingValueTreatment::CONTINUE:
1253 pVal = "span";
1254 break;
1255 default:
1256 SAL_WARN("oox", "unknown MissingValueTreatment value");
1257 break;
1258 }
1259
1260 FSHelperPtr pFS = GetFS();
1261 pFS->singleElement(FSNS(XML_c, XML_dispBlanksAs), XML_val, pVal);
1262}
1263
1265{
1266 FSHelperPtr pFS = GetFS();
1267 pFS->startElement(FSNS(XML_c, XML_legend));
1268
1269 Reference< beans::XPropertySet > xProp( xChartDoc->getLegend(), uno::UNO_QUERY );
1270 if( xProp.is() )
1271 {
1272 // position
1273 css::chart::ChartLegendPosition aLegendPos = css::chart::ChartLegendPosition_NONE;
1274 try
1275 {
1276 Any aAny( xProp->getPropertyValue( "Alignment" ));
1277 aAny >>= aLegendPos;
1278 }
1279 catch( beans::UnknownPropertyException & )
1280 {
1281 SAL_WARN("oox", "Property Align not found in ChartLegend");
1282 }
1283
1284 const char* strPos = nullptr;
1285 switch( aLegendPos )
1286 {
1287 case css::chart::ChartLegendPosition_LEFT:
1288 strPos = "l";
1289 break;
1290 case css::chart::ChartLegendPosition_RIGHT:
1291 strPos = "r";
1292 break;
1293 case css::chart::ChartLegendPosition_TOP:
1294 strPos = "t";
1295 break;
1296 case css::chart::ChartLegendPosition_BOTTOM:
1297 strPos = "b";
1298 break;
1299 case css::chart::ChartLegendPosition_NONE:
1300 case css::chart::ChartLegendPosition::ChartLegendPosition_MAKE_FIXED_SIZE:
1301 // nothing
1302 break;
1303 }
1304
1305 if( strPos != nullptr )
1306 {
1307 pFS->singleElement(FSNS(XML_c, XML_legendPos), XML_val, strPos);
1308 }
1309
1310 // legendEntry
1311 Reference<chart2::XCoordinateSystemContainer> xCooSysContainer(mxNewDiagram, UNO_QUERY_THROW);
1312 const Sequence<Reference<chart2::XCoordinateSystem>> xCooSysSequence(xCooSysContainer->getCoordinateSystems());
1313
1314 sal_Int32 nIndex = 0;
1315 bool bShowLegendEntry;
1316 for (const auto& rCooSys : xCooSysSequence)
1317 {
1318 PropertySet aCooSysProp(rCooSys);
1319 bool bSwapXAndY = aCooSysProp.getBoolProperty(PROP_SwapXAndYAxis);
1320
1321 Reference<chart2::XChartTypeContainer> xChartTypeContainer(rCooSys, UNO_QUERY_THROW);
1322 const Sequence<Reference<chart2::XChartType>> xChartTypeSequence(xChartTypeContainer->getChartTypes());
1323 if (!xChartTypeSequence.hasElements())
1324 continue;
1325
1326 for (const auto& rCT : xChartTypeSequence)
1327 {
1328 Reference<chart2::XDataSeriesContainer> xDSCont(rCT, UNO_QUERY);
1329 if (!xDSCont.is())
1330 continue;
1331
1332 OUString aChartType(rCT->getChartType());
1333 bool bIsPie = lcl_getChartType(aChartType) == chart::TYPEID_PIE;
1334 if (bIsPie)
1335 {
1336 PropertySet xChartTypeProp(rCT);
1337 bIsPie = !xChartTypeProp.getBoolProperty(PROP_UseRings);
1338 }
1339 const Sequence<Reference<chart2::XDataSeries>> aDataSeriesSeq = xDSCont->getDataSeries();
1340 if (bSwapXAndY)
1341 nIndex += aDataSeriesSeq.getLength() - 1;
1342 for (const auto& rDataSeries : aDataSeriesSeq)
1343 {
1344 PropertySet aSeriesProp(rDataSeries);
1345 bool bVaryColorsByPoint = aSeriesProp.getBoolProperty(PROP_VaryColorsByPoint);
1346 if (bVaryColorsByPoint || bIsPie)
1347 {
1348 Sequence<sal_Int32> deletedLegendEntriesSeq;
1349 aSeriesProp.getProperty(deletedLegendEntriesSeq, PROP_DeletedLegendEntries);
1350 for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq))
1351 {
1352 pFS->startElement(FSNS(XML_c, XML_legendEntry));
1353 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val,
1354 OString::number(nIndex + deletedLegendEntry));
1355 pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, "1");
1356 pFS->endElement(FSNS(XML_c, XML_legendEntry));
1357 }
1358 Reference<chart2::data::XDataSource> xDSrc(rDataSeries, UNO_QUERY);
1359 if (!xDSrc.is())
1360 continue;
1361
1362 const Sequence<Reference<chart2::data::XLabeledDataSequence>> aDataSeqs = xDSrc->getDataSequences();
1363 for (const auto& rDataSeq : aDataSeqs)
1364 {
1365 Reference<chart2::data::XDataSequence> xValues = rDataSeq->getValues();
1366 if (!xValues.is())
1367 continue;
1368
1369 sal_Int32 nDataSeqSize = xValues->getData().getLength();
1370 nIndex += nDataSeqSize;
1371 }
1372 }
1373 else
1374 {
1375 bShowLegendEntry = aSeriesProp.getBoolProperty(PROP_ShowLegendEntry);
1376 if (!bShowLegendEntry)
1377 {
1378 pFS->startElement(FSNS(XML_c, XML_legendEntry));
1379 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val,
1380 OString::number(nIndex));
1381 pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, "1");
1382 pFS->endElement(FSNS(XML_c, XML_legendEntry));
1383 }
1384 bSwapXAndY ? nIndex-- : nIndex++;
1385 }
1386 }
1387 if (bSwapXAndY)
1388 nIndex += aDataSeriesSeq.getLength() + 1;
1389 }
1390 }
1391
1392 uno::Any aRelativePos = xProp->getPropertyValue("RelativePosition");
1393 if (aRelativePos.hasValue())
1394 {
1395 pFS->startElement(FSNS(XML_c, XML_layout));
1396 pFS->startElement(FSNS(XML_c, XML_manualLayout));
1397
1398 pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1399 pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1400 chart2::RelativePosition aPos = aRelativePos.get<chart2::RelativePosition>();
1401
1402 const double x = aPos.Primary;
1403 const double y = aPos.Secondary;
1404
1405 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1406 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1407
1408 uno::Any aRelativeSize = xProp->getPropertyValue("RelativeSize");
1409 if (aRelativeSize.hasValue())
1410 {
1411 chart2::RelativeSize aSize = aRelativeSize.get<chart2::RelativeSize>();
1412
1413 const double w = aSize.Primary;
1414 const double h = aSize.Secondary;
1415
1416 pFS->singleElement(FSNS(XML_c, XML_w), XML_val, OString::number(w));
1417
1418 pFS->singleElement(FSNS(XML_c, XML_h), XML_val, OString::number(h));
1419 }
1420
1421 SAL_WARN_IF(aPos.Anchor != css::drawing::Alignment_TOP_LEFT, "oox", "unsupported anchor position");
1422
1423 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1424 pFS->endElement(FSNS(XML_c, XML_layout));
1425 }
1426
1427 if (strPos != nullptr)
1428 {
1429 uno::Any aOverlay = xProp->getPropertyValue("Overlay");
1430 if(aOverlay.get<bool>())
1431 pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "1");
1432 else
1433 pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "0");
1434 }
1435
1436 // shape properties
1437 exportShapeProps( xProp );
1438
1439 // draw-chart:txPr text properties
1440 exportTextProps( xProp );
1441 }
1442
1443 pFS->endElement( FSNS( XML_c, XML_legend ) );
1444}
1445
1446void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString* pSubText)
1447{
1448 OUString sText;
1449 Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1450 if( xPropSet.is())
1451 {
1452 xPropSet->getPropertyValue("String") >>= sText;
1453 }
1454
1455 // tdf#101322: add subtitle to title
1456 if( pSubText )
1457 sText = sText.isEmpty() ? *pSubText : sText + "\n" + *pSubText;
1458
1459 if( sText.isEmpty() )
1460 return;
1461
1462 FSHelperPtr pFS = GetFS();
1463 pFS->startElement(FSNS(XML_c, XML_title));
1464
1465 pFS->startElement(FSNS(XML_c, XML_tx));
1466 pFS->startElement(FSNS(XML_c, XML_rich));
1467
1468 // TODO: bodyPr
1469 const char* sWritingMode = nullptr;
1470 bool bVertical = false;
1471 xPropSet->getPropertyValue("StackedText") >>= bVertical;
1472 if( bVertical )
1473 sWritingMode = "wordArtVert";
1474
1475 sal_Int32 nRotation = 0;
1476 xPropSet->getPropertyValue("TextRotation") >>= nRotation;
1477
1478 pFS->singleElement( FSNS( XML_a, XML_bodyPr ),
1479 XML_vert, sWritingMode,
1480 XML_rot, oox::drawingml::calcRotationValue(nRotation) );
1481 // TODO: lstStyle
1482 pFS->singleElement(FSNS(XML_a, XML_lstStyle));
1483 // FIXME: handle multiple paragraphs to parse aText
1484 pFS->startElement(FSNS(XML_a, XML_p));
1485
1486 pFS->startElement(FSNS(XML_a, XML_pPr));
1487
1488 bool bDummy = false;
1489 sal_Int32 nDummy;
1490 WriteRunProperties(xPropSet, false, XML_defRPr, true, bDummy, nDummy );
1491
1492 pFS->endElement( FSNS( XML_a, XML_pPr ) );
1493
1494 pFS->startElement(FSNS(XML_a, XML_r));
1495 bDummy = false;
1496 WriteRunProperties( xPropSet, false, XML_rPr, true, bDummy, nDummy );
1497 pFS->startElement(FSNS(XML_a, XML_t));
1498 pFS->writeEscaped( sText );
1499 pFS->endElement( FSNS( XML_a, XML_t ) );
1500 pFS->endElement( FSNS( XML_a, XML_r ) );
1501
1502 pFS->endElement( FSNS( XML_a, XML_p ) );
1503
1504 pFS->endElement( FSNS( XML_c, XML_rich ) );
1505 pFS->endElement( FSNS( XML_c, XML_tx ) );
1506
1507 uno::Any aManualLayout = xPropSet->getPropertyValue("RelativePosition");
1508 if (aManualLayout.hasValue())
1509 {
1510 pFS->startElement(FSNS(XML_c, XML_layout));
1511 pFS->startElement(FSNS(XML_c, XML_manualLayout));
1512 pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1513 pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1514
1515 Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1516 awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1517
1518 awt::Size aSize = xShape->getSize();
1519 awt::Point aPos2 = xShape->getPosition();
1520 // rotated shapes need special handling...
1521 double fSin = fabs(sin(basegfx::deg2rad<100>(nRotation)));
1522 // remove part of height from X direction, if title is rotated down
1523 if( nRotation*0.01 > 180.0 )
1524 aPos2.X -= static_cast<sal_Int32>(fSin * aSize.Height + 0.5);
1525 // remove part of width from Y direction, if title is rotated up
1526 else if( nRotation*0.01 > 0.0 )
1527 aPos2.Y -= static_cast<sal_Int32>(fSin * aSize.Width + 0.5);
1528
1529 double x = static_cast<double>(aPos2.X) / static_cast<double>(aPageSize.Width);
1530 double y = static_cast<double>(aPos2.Y) / static_cast<double>(aPageSize.Height);
1531 /*
1532 pFS->singleElement(FSNS(XML_c, XML_wMode), XML_val, "edge");
1533 pFS->singleElement(FSNS(XML_c, XML_hMode), XML_val, "edge");
1534 */
1535 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1536 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1537 /*
1538 pFS->singleElement(FSNS(XML_c, XML_w), XML_val, "");
1539 pFS->singleElement(FSNS(XML_c, XML_h), XML_val, "");
1540 */
1541 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1542 pFS->endElement(FSNS(XML_c, XML_layout));
1543 }
1544
1545 pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "0");
1546
1547 // shape properties
1548 if( xPropSet.is() )
1549 {
1550 exportShapeProps( xPropSet );
1551 }
1552
1553 pFS->endElement( FSNS( XML_c, XML_title ) );
1554}
1555
1556namespace {
1557
1558 std::vector<Sequence<Reference<chart2::XDataSeries> > > splitDataSeriesByAxis(const Reference< chart2::XChartType >& xChartType)
1559 {
1560 std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitSeries;
1561 std::map<sal_Int32, size_t> aMapAxisToIndex;
1562
1563 Reference< chart2::XDataSeriesContainer > xDSCnt(xChartType, uno::UNO_QUERY);
1564 if (xDSCnt.is())
1565 {
1566 sal_Int32 nAxisIndexOfFirstSeries = -1;
1567 const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq(xDSCnt->getDataSeries());
1568 for (const uno::Reference<chart2::XDataSeries>& xSeries : aSeriesSeq)
1569 {
1570 Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
1571 if (!xPropSet.is())
1572 continue;
1573
1574 sal_Int32 nAxisIndex = -1;
1575 uno::Any aAny = xPropSet->getPropertyValue("AttachedAxisIndex");
1576 aAny >>= nAxisIndex;
1577 size_t nVectorPos = 0;
1578 if (nAxisIndexOfFirstSeries == -1)
1579 {
1580 nAxisIndexOfFirstSeries = nAxisIndex;
1581 }
1582
1583 auto it = aMapAxisToIndex.find(nAxisIndex);
1584 if (it == aMapAxisToIndex.end())
1585 {
1586 aSplitSeries.emplace_back();
1587 nVectorPos = aSplitSeries.size() - 1;
1588 aMapAxisToIndex.insert(std::pair<sal_Int32, size_t>(nAxisIndex, nVectorPos));
1589 }
1590 else
1591 {
1592 nVectorPos = it->second;
1593 }
1594
1595 uno::Sequence<Reference<chart2::XDataSeries> >& rAxisSeriesSeq = aSplitSeries[nVectorPos];
1596 sal_Int32 nLength = rAxisSeriesSeq.getLength();
1597 rAxisSeriesSeq.realloc(nLength + 1);
1598 rAxisSeriesSeq.getArray()[nLength] = xSeries;
1599 }
1600 // if the first series attached to secondary axis, then export those series first, which are attached to primary axis
1601 // also the MS Office export every time in this order
1602 if (aSplitSeries.size() > 1 && nAxisIndexOfFirstSeries == 1)
1603 {
1604 std::swap(aSplitSeries[0], aSplitSeries[1]);
1605 }
1606 }
1607
1608 return aSplitSeries;
1609 }
1610
1611}
1612
1614{
1616 if( ! xBCooSysCnt.is())
1617 return;
1618
1619 // plot-area element
1620
1621 FSHelperPtr pFS = GetFS();
1622 pFS->startElement(FSNS(XML_c, XML_plotArea));
1623
1624 Reference<beans::XPropertySet> xWall(mxNewDiagram, uno::UNO_QUERY);
1625 if( xWall.is() )
1626 {
1627 uno::Any aAny = xWall->getPropertyValue("RelativePosition");
1628 if (aAny.hasValue())
1629 {
1630 chart2::RelativePosition aPos = aAny.get<chart2::RelativePosition>();
1631 aAny = xWall->getPropertyValue("RelativeSize");
1632 chart2::RelativeSize aSize = aAny.get<chart2::RelativeSize>();
1633 uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( xChartDoc->getDiagram(), uno::UNO_QUERY );
1634 exportManualLayout(aPos, aSize, xDiagramPositioning->isExcludingDiagramPositioning() );
1635 }
1636 }
1637
1638 // chart type
1640 aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
1641
1642 // tdf#123647 Save empty chart as empty bar chart.
1643 if (!aCooSysSeq.hasElements())
1644 {
1645 pFS->startElement(FSNS(XML_c, XML_barChart));
1646 pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, "col");
1647 pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, "clustered");
1648 pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
1649 exportAxesId(true);
1650 pFS->endElement(FSNS(XML_c, XML_barChart));
1651 }
1652
1653 for( const auto& rCS : aCooSysSeq )
1654 {
1655 Reference< chart2::XChartTypeContainer > xCTCnt( rCS, uno::UNO_QUERY );
1656 if( ! xCTCnt.is())
1657 continue;
1658 mnSeriesCount=0;
1659 const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
1660 for( const auto& rCT : aCTSeq )
1661 {
1662 Reference< chart2::XDataSeriesContainer > xDSCnt( rCT, uno::UNO_QUERY );
1663 if( ! xDSCnt.is())
1664 return;
1665 Reference< chart2::XChartType > xChartType( rCT, uno::UNO_QUERY );
1666 if( ! xChartType.is())
1667 continue;
1668 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
1669 OUString aChartType( xChartType->getChartType());
1670 sal_Int32 eChartType = lcl_getChartType( aChartType );
1671 switch( eChartType )
1672 {
1673 case chart::TYPEID_BAR:
1674 {
1675 exportBarChart( xChartType );
1676 break;
1677 }
1678 case chart::TYPEID_AREA:
1679 {
1680 exportAreaChart( xChartType );
1681 break;
1682 }
1683 case chart::TYPEID_LINE:
1684 {
1685 exportLineChart( xChartType );
1686 break;
1687 }
1689 {
1690 exportBubbleChart( xChartType );
1691 break;
1692 }
1694 {
1695 break;
1696 }
1698 case chart::TYPEID_PIE:
1699 {
1700 exportPieChart( xChartType );
1701 break;
1702 }
1705 {
1706 exportRadarChart( xChartType );
1707 break;
1708 }
1710 {
1711 exportScatterChart( xChartType );
1712 break;
1713 }
1715 {
1716 exportStockChart( xChartType );
1717 break;
1718 }
1720 {
1721 exportSurfaceChart( xChartType );
1722 break;
1723 }
1724 default:
1725 {
1726 SAL_WARN("oox", "ChartExport::exportPlotArea -- not support chart type");
1727 break;
1728 }
1729 }
1730
1731 }
1732 }
1733 //Axis Data
1734 exportAxes( );
1735
1736 // Data Table
1738
1739 // shape properties
1740 /*
1741 * Export the Plot area Shape Properties
1742 * eg: Fill and Outline
1743 */
1744 Reference< css::chart::X3DDisplay > xWallFloorSupplier( mxDiagram, uno::UNO_QUERY );
1745 // tdf#114139 For 2D charts Plot Area equivalent is Chart Wall.
1746 // Unfortunately LibreOffice doesn't have Plot Area equivalent for 3D charts.
1747 // It means that Plot Area couldn't be displayed and changed for 3D chars in LibreOffice.
1748 // We cannot write Wall attributes into Plot Area for 3D charts, because Wall us used as background wall.
1749 if( !mbIs3DChart && xWallFloorSupplier.is() )
1750 {
1751 Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall();
1752 if( xWallPropSet.is() )
1753 {
1754 uno::Any aAny = xWallPropSet->getPropertyValue("LineStyle");
1755 sal_Int32 eChartType = getChartType( );
1756 // Export LineStyle_NONE instead of default linestyle of PlotArea border, because LibreOffice
1757 // make invisible the Wall shape properties, in case of these charts. Or in the future set
1758 // the default LineStyle of these charts to LineStyle_NONE.
1759 bool noSupportWallProp = ( (eChartType == chart::TYPEID_PIE) || (eChartType == chart::TYPEID_RADARLINE) || (eChartType == chart::TYPEID_RADARAREA) );
1760 if ( noSupportWallProp && (aAny != drawing::LineStyle_NONE) )
1761 {
1762 xWallPropSet->setPropertyValue( "LineStyle", uno::Any(drawing::LineStyle_NONE) );
1763 }
1764 exportShapeProps( xWallPropSet );
1765 }
1766 }
1767
1768 pFS->endElement( FSNS( XML_c, XML_plotArea ) );
1769
1770}
1771
1772void ChartExport::exportManualLayout(const css::chart2::RelativePosition& rPos,
1773 const css::chart2::RelativeSize& rSize,
1774 const bool bIsExcludingDiagramPositioning)
1775{
1776 FSHelperPtr pFS = GetFS();
1777 pFS->startElement(FSNS(XML_c, XML_layout));
1778 pFS->startElement(FSNS(XML_c, XML_manualLayout));
1779
1780 // By default layoutTarget is set to "outer" and we shouldn't save it in that case
1781 if ( bIsExcludingDiagramPositioning )
1782 {
1783 pFS->singleElement(FSNS(XML_c, XML_layoutTarget), XML_val, "inner");
1784 }
1785 pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1786 pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1787
1788 double x = rPos.Primary;
1789 double y = rPos.Secondary;
1790 const double w = rSize.Primary;
1791 const double h = rSize.Secondary;
1792 switch (rPos.Anchor)
1793 {
1794 case drawing::Alignment_LEFT:
1795 y -= (h/2);
1796 break;
1797 case drawing::Alignment_TOP_LEFT:
1798 break;
1799 case drawing::Alignment_BOTTOM_LEFT:
1800 y -= h;
1801 break;
1802 case drawing::Alignment_TOP:
1803 x -= (w/2);
1804 break;
1805 case drawing::Alignment_CENTER:
1806 x -= (w/2);
1807 y -= (h/2);
1808 break;
1809 case drawing::Alignment_BOTTOM:
1810 x -= (w/2);
1811 y -= h;
1812 break;
1813 case drawing::Alignment_TOP_RIGHT:
1814 x -= w;
1815 break;
1816 case drawing::Alignment_BOTTOM_RIGHT:
1817 x -= w;
1818 y -= h;
1819 break;
1820 case drawing::Alignment_RIGHT:
1821 y -= (h/2);
1822 x -= w;
1823 break;
1824 default:
1825 SAL_WARN("oox", "unhandled alignment case for manual layout export " << static_cast<sal_uInt16>(rPos.Anchor));
1826 }
1827
1828 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1829
1830 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1831
1832 pFS->singleElement(FSNS(XML_c, XML_w), XML_val, OString::number(w));
1833
1834 pFS->singleElement(FSNS(XML_c, XML_h), XML_val, OString::number(h));
1835
1836 pFS->endElement(FSNS(XML_c, XML_manualLayout));
1837 pFS->endElement(FSNS(XML_c, XML_layout));
1838}
1839
1841{
1842 // Similar to DrawingML::WriteFill, but gradient access via name
1843 if (!GetProperty( xPropSet, "FillStyle" ))
1844 return;
1845 FillStyle aFillStyle(FillStyle_NONE);
1846 mAny >>= aFillStyle;
1847
1848 // map full transparent background to no fill
1849 if (aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ))
1850 {
1851 sal_Int16 nVal = 0;
1852 mAny >>= nVal;
1853 if ( nVal == 100 )
1854 aFillStyle = FillStyle_NONE;
1855 }
1856 OUString sFillTransparenceGradientName;
1857 if (aFillStyle == FillStyle_SOLID
1858 && GetProperty(xPropSet, "FillTransparenceGradientName") && (mAny >>= sFillTransparenceGradientName)
1859 && !sFillTransparenceGradientName.isEmpty())
1860 {
1861 awt::Gradient aTransparenceGradient;
1862 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1863 uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1864 uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1865 rTransparenceValue >>= aTransparenceGradient;
1866 if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff)
1867 aFillStyle = FillStyle_NONE;
1868 }
1869 switch( aFillStyle )
1870 {
1871 case FillStyle_SOLID:
1872 exportSolidFill(xPropSet);
1873 break;
1874 case FillStyle_GRADIENT :
1875 exportGradientFill( xPropSet );
1876 break;
1877 case FillStyle_BITMAP :
1878 exportBitmapFill( xPropSet );
1879 break;
1880 case FillStyle_HATCH:
1881 exportHatch(xPropSet);
1882 break;
1883 case FillStyle_NONE:
1884 mpFS->singleElementNS(XML_a, XML_noFill);
1885 break;
1886 default:
1887 ;
1888 }
1889}
1890
1892{
1893 // Similar to DrawingML::WriteSolidFill, but gradient access via name
1894 // and currently no InteropGrabBag
1895 // get fill color
1896 if (!GetProperty( xPropSet, "FillColor" ))
1897 return;
1898 sal_uInt32 nFillColor = mAny.get<sal_uInt32>();
1899
1900 sal_Int32 nAlpha = MAX_PERCENT;
1901 if (GetProperty( xPropSet, "FillTransparence" ))
1902 {
1903 sal_Int32 nTransparency = 0;
1904 mAny >>= nTransparency;
1905 // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
1906 nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
1907 }
1908 // OOXML has no separate transparence gradient but uses transparency in the gradient stops.
1909 // So we merge transparency and color and use gradient fill in such case.
1910 awt::Gradient aTransparenceGradient;
1911 bool bNeedGradientFill(false);
1912 OUString sFillTransparenceGradientName;
1913 if (GetProperty(xPropSet, "FillTransparenceGradientName")
1914 && (mAny >>= sFillTransparenceGradientName)
1915 && !sFillTransparenceGradientName.isEmpty())
1916 {
1917 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1918 uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1919 uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1920 rTransparenceValue >>= aTransparenceGradient;
1921 if (aTransparenceGradient.StartColor != aTransparenceGradient.EndColor)
1922 bNeedGradientFill = true;
1923 else if (aTransparenceGradient.StartColor != 0)
1924 nAlpha = lcl_getAlphaFromTransparenceGradient(aTransparenceGradient, true);
1925 }
1926 // write XML
1927 if (bNeedGradientFill)
1928 {
1929 awt::Gradient aPseudoColorGradient;
1930 aPseudoColorGradient.XOffset = aTransparenceGradient.XOffset;
1931 aPseudoColorGradient.YOffset = aTransparenceGradient.YOffset;
1932 aPseudoColorGradient.StartIntensity = 100;
1933 aPseudoColorGradient.EndIntensity = 100;
1934 aPseudoColorGradient.Angle = aTransparenceGradient.Angle;
1935 aPseudoColorGradient.Border = aTransparenceGradient.Border;
1936 aPseudoColorGradient.Style = aTransparenceGradient.Style;
1937 aPseudoColorGradient.StartColor = nFillColor;
1938 aPseudoColorGradient.EndColor = nFillColor;
1939 aPseudoColorGradient.StepCount = aTransparenceGradient.StepCount;
1940 mpFS->startElementNS(XML_a, XML_gradFill, XML_rotWithShape, "0");
1941 WriteGradientFill(aPseudoColorGradient, aTransparenceGradient);
1942 mpFS->endElementNS(XML_a, XML_gradFill);
1943 }
1944 else
1945 WriteSolidFill(::Color(ColorTransparency, nFillColor & 0xffffff), nAlpha);
1946}
1947
1949{
1950 if (!xPropSet.is())
1951 return;
1952
1953 if (GetProperty(xPropSet, "FillHatchName"))
1954 {
1955 OUString aHatchName;
1956 mAny >>= aHatchName;
1957 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1958 uno::Reference< container::XNameAccess > xHatchTable( xFact->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY );
1959 uno::Any rValue = xHatchTable->getByName(aHatchName);
1960 css::drawing::Hatch aHatch;
1961 rValue >>= aHatch;
1962 WritePattFill(xPropSet, aHatch);
1963 }
1964
1965}
1966
1968{
1969 if( !xPropSet.is() )
1970 return;
1971
1972 OUString sFillBitmapName;
1973 xPropSet->getPropertyValue("FillBitmapName") >>= sFillBitmapName;
1974
1975 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1976 try
1977 {
1978 uno::Reference< container::XNameAccess > xBitmapTable( xFact->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY );
1979 uno::Any rValue = xBitmapTable->getByName( sFillBitmapName );
1980 if (rValue.has<uno::Reference<awt::XBitmap>>())
1981 {
1982 uno::Reference<awt::XBitmap> xBitmap = rValue.get<uno::Reference<awt::XBitmap>>();
1983 uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1984 if (xGraphic.is())
1985 {
1986 WriteXGraphicBlipFill(xPropSet, xGraphic, XML_a, true, true);
1987 }
1988 }
1989 }
1990 catch (const uno::Exception &)
1991 {
1992 TOOLS_WARN_EXCEPTION("oox", "ChartExport::exportBitmapFill");
1993 }
1994}
1995
1997{
1998 if( !xPropSet.is() )
1999 return;
2000
2001 OUString sFillGradientName;
2002 xPropSet->getPropertyValue("FillGradientName") >>= sFillGradientName;
2003
2004 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
2005 try
2006 {
2007 uno::Reference< container::XNameAccess > xGradient( xFact->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY );
2008 uno::Any rGradientValue = xGradient->getByName( sFillGradientName );
2009 awt::Gradient aGradient;
2010 if( rGradientValue >>= aGradient )
2011 {
2012 awt::Gradient aTransparenceGradient;
2013 mpFS->startElementNS(XML_a, XML_gradFill);
2014 OUString sFillTransparenceGradientName;
2015 if( (xPropSet->getPropertyValue("FillTransparenceGradientName") >>= sFillTransparenceGradientName) && !sFillTransparenceGradientName.isEmpty())
2016 {
2017 uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
2018 uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
2019 rTransparenceValue >>= aTransparenceGradient;
2020 WriteGradientFill(aGradient, aTransparenceGradient);
2021 }
2022 else
2023 {
2024 WriteGradientFill(aGradient, aTransparenceGradient, xPropSet);
2025 }
2026 mpFS->endElementNS(XML_a, XML_gradFill);
2027 }
2028 }
2029 catch (const uno::Exception &)
2030 {
2031 TOOLS_INFO_EXCEPTION("oox", "ChartExport::exportGradientFill");
2032 }
2033}
2034
2036{
2037 auto xDataTable = mxNewDiagram->getDataTable();
2038 if (!xDataTable.is())
2039 return;
2040
2041 FSHelperPtr pFS = GetFS();
2042 uno::Reference<beans::XPropertySet> aPropSet(xDataTable, uno::UNO_QUERY);
2043
2044 bool bShowVBorder = false;
2045 bool bShowHBorder = false;
2046 bool bShowOutline = false;
2047 bool bShowKeys = false;
2048
2049 if (GetProperty(aPropSet, "HBorder"))
2050 mAny >>= bShowHBorder;
2051 if (GetProperty(aPropSet, "VBorder"))
2052 mAny >>= bShowVBorder;
2053 if (GetProperty(aPropSet, "Outline"))
2054 mAny >>= bShowOutline;
2055 if (GetProperty(aPropSet, "Keys"))
2056 mAny >>= bShowKeys;
2057
2058 pFS->startElement(FSNS(XML_c, XML_dTable));
2059
2060 if (bShowHBorder)
2061 pFS->singleElement(FSNS(XML_c, XML_showHorzBorder), XML_val, "1" );
2062 if (bShowVBorder)
2063 pFS->singleElement(FSNS(XML_c, XML_showVertBorder), XML_val, "1");
2064 if (bShowOutline)
2065 pFS->singleElement(FSNS(XML_c, XML_showOutline), XML_val, "1");
2066 if (bShowKeys)
2067 pFS->singleElement(FSNS(XML_c, XML_showKeys), XML_val, "1");
2068
2069 exportShapeProps(aPropSet);
2070 exportTextProps(aPropSet);
2071
2072 pFS->endElement(FSNS(XML_c, XML_dTable));
2073}
2074
2076{
2077 FSHelperPtr pFS = GetFS();
2078 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2079 for (const auto& splitDataSeries : aSplitDataSeries)
2080 {
2081 if (!splitDataSeries.hasElements())
2082 continue;
2083
2084 sal_Int32 nTypeId = XML_areaChart;
2085 if (mbIs3DChart)
2086 nTypeId = XML_area3DChart;
2087 pFS->startElement(FSNS(XML_c, nTypeId));
2088
2090 bool bPrimaryAxes = true;
2091 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2092 exportAxesId(bPrimaryAxes);
2093
2094 pFS->endElement(FSNS(XML_c, nTypeId));
2095 }
2096}
2097
2099{
2100 sal_Int32 nTypeId = XML_barChart;
2101 if (mbIs3DChart)
2102 nTypeId = XML_bar3DChart;
2103 FSHelperPtr pFS = GetFS();
2104
2105 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2106 for (const auto& splitDataSeries : aSplitDataSeries)
2107 {
2108 if (!splitDataSeries.hasElements())
2109 continue;
2110
2111 pFS->startElement(FSNS(XML_c, nTypeId));
2112 // bar direction
2113 bool bVertical = false;
2114 Reference< XPropertySet > xPropSet(mxDiagram, uno::UNO_QUERY);
2115 if (GetProperty(xPropSet, "Vertical"))
2116 mAny >>= bVertical;
2117
2118 const char* bardir = bVertical ? "bar" : "col";
2119 pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, bardir);
2120
2121 exportGrouping(true);
2122
2123 exportVaryColors(xChartType);
2124
2125 bool bPrimaryAxes = true;
2126 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2127
2128 Reference< XPropertySet > xTypeProp(xChartType, uno::UNO_QUERY);
2129
2130 if (xTypeProp.is() && GetProperty(xTypeProp, "GapwidthSequence"))
2131 {
2132 uno::Sequence< sal_Int32 > aBarPositionSequence;
2133 mAny >>= aBarPositionSequence;
2134 if (aBarPositionSequence.hasElements())
2135 {
2136 sal_Int32 nGapWidth = aBarPositionSequence[0];
2137 pFS->singleElement(FSNS(XML_c, XML_gapWidth), XML_val, OString::number(nGapWidth));
2138 }
2139 }
2140
2141 if (mbIs3DChart)
2142 {
2143 // Shape
2144 namespace cssc = css::chart;
2145 sal_Int32 nGeom3d = cssc::ChartSolidType::RECTANGULAR_SOLID;
2146 if (xPropSet.is() && GetProperty(xPropSet, "SolidType"))
2147 mAny >>= nGeom3d;
2148 const char* sShapeType = nullptr;
2149 switch (nGeom3d)
2150 {
2151 case cssc::ChartSolidType::RECTANGULAR_SOLID:
2152 sShapeType = "box";
2153 break;
2154 case cssc::ChartSolidType::CONE:
2155 sShapeType = "cone";
2156 break;
2157 case cssc::ChartSolidType::CYLINDER:
2158 sShapeType = "cylinder";
2159 break;
2160 case cssc::ChartSolidType::PYRAMID:
2161 sShapeType = "pyramid";
2162 break;
2163 }
2164 pFS->singleElement(FSNS(XML_c, XML_shape), XML_val, sShapeType);
2165 }
2166
2167 //overlap
2168 if (!mbIs3DChart && xTypeProp.is() && GetProperty(xTypeProp, "OverlapSequence"))
2169 {
2170 uno::Sequence< sal_Int32 > aBarPositionSequence;
2171 mAny >>= aBarPositionSequence;
2172 if (aBarPositionSequence.hasElements())
2173 {
2174 sal_Int32 nOverlap = aBarPositionSequence[0];
2175 // Stacked/Percent Bar/Column chart Overlap-workaround
2176 // Export the Overlap value with 100% for stacked charts,
2177 // because the default overlap value of the Bar/Column chart is 0% and
2178 // LibreOffice do nothing with the overlap value in Stacked charts case,
2179 // unlike the MS Office, which is interpreted differently.
2180 if ((mbStacked || mbPercent) && nOverlap != 100)
2181 {
2182 nOverlap = 100;
2183 pFS->singleElement(FSNS(XML_c, XML_overlap), XML_val, OString::number(nOverlap));
2184 }
2185 else // Normal bar chart
2186 {
2187 pFS->singleElement(FSNS(XML_c, XML_overlap), XML_val, OString::number(nOverlap));
2188 }
2189 }
2190 }
2191
2192 exportAxesId(bPrimaryAxes);
2193
2194 pFS->endElement(FSNS(XML_c, nTypeId));
2195 }
2196}
2197
2199{
2200 FSHelperPtr pFS = GetFS();
2201 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2202 for (const auto& splitDataSeries : aSplitDataSeries)
2203 {
2204 if (!splitDataSeries.hasElements())
2205 continue;
2206
2207 pFS->startElement(FSNS(XML_c, XML_bubbleChart));
2208
2209 exportVaryColors(xChartType);
2210
2211 bool bPrimaryAxes = true;
2212 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2213
2214 exportAxesId(bPrimaryAxes);
2215
2216 pFS->endElement(FSNS(XML_c, XML_bubbleChart));
2217 }
2218}
2219
2221{
2222 FSHelperPtr pFS = GetFS();
2223 pFS->startElement(FSNS(XML_c, XML_doughnutChart));
2224
2225 exportVaryColors(xChartType);
2226
2227 bool bPrimaryAxes = true;
2228 exportAllSeries(xChartType, bPrimaryAxes);
2229 // firstSliceAng
2231 //FIXME: holeSize
2232 pFS->singleElement(FSNS(XML_c, XML_holeSize), XML_val, OString::number(50));
2233
2234 pFS->endElement( FSNS( XML_c, XML_doughnutChart ) );
2235}
2236
2237namespace {
2238
2239void writeDataLabelsRange(const FSHelperPtr& pFS, const XmlFilterBase* pFB, DataLabelsRange& rDLblsRange)
2240{
2241 if (rDLblsRange.empty())
2242 return;
2243
2244 pFS->startElement(FSNS(XML_c, XML_extLst));
2245 pFS->startElement(FSNS(XML_c, XML_ext), XML_uri, "{02D57815-91ED-43cb-92C2-25804820EDAC}", FSNS(XML_xmlns, XML_c15), pFB->getNamespaceURL(OOX_NS(c15)));
2246 pFS->startElement(FSNS(XML_c15, XML_datalabelsRange));
2247
2248 // Write cell range.
2249 pFS->startElement(FSNS(XML_c15, XML_f));
2250 pFS->writeEscaped(rDLblsRange.getRange());
2251 pFS->endElement(FSNS(XML_c15, XML_f));
2252
2253 // Write all labels.
2254 pFS->startElement(FSNS(XML_c15, XML_dlblRangeCache));
2255 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(rDLblsRange.count()));
2256 for (const auto& rLabelKV: rDLblsRange)
2257 {
2258 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(rLabelKV.first));
2259 pFS->startElement(FSNS(XML_c, XML_v));
2260 pFS->writeEscaped(rLabelKV.second);
2261 pFS->endElement(FSNS( XML_c, XML_v ));
2262 pFS->endElement(FSNS(XML_c, XML_pt));
2263 }
2264
2265 pFS->endElement(FSNS(XML_c15, XML_dlblRangeCache));
2266
2267 pFS->endElement(FSNS(XML_c15, XML_datalabelsRange));
2268 pFS->endElement(FSNS(XML_c, XML_ext));
2269 pFS->endElement(FSNS(XML_c, XML_extLst));
2270}
2271
2272}
2273
2275{
2276 FSHelperPtr pFS = GetFS();
2277 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2278 for (const auto& splitDataSeries : aSplitDataSeries)
2279 {
2280 if (!splitDataSeries.hasElements())
2281 continue;
2282
2283 sal_Int32 nTypeId = XML_lineChart;
2284 if( mbIs3DChart )
2285 nTypeId = XML_line3DChart;
2286 pFS->startElement(FSNS(XML_c, nTypeId));
2287
2288 exportGrouping( );
2289
2290 exportVaryColors(xChartType);
2291 // TODO: show marker symbol in series?
2292 bool bPrimaryAxes = true;
2293 exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2294
2295 // show marker?
2296 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
2297 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
2298 if( GetProperty( xPropSet, "SymbolType" ) )
2299 mAny >>= nSymbolType;
2300
2301 if( !mbIs3DChart )
2302 {
2304 exportUpDownBars(xChartType);
2305 const char* marker = nSymbolType == css::chart::ChartSymbolType::NONE? "0":"1";
2306 pFS->singleElement(FSNS(XML_c, XML_marker), XML_val, marker);
2307 }
2308
2309 exportAxesId(bPrimaryAxes, true);
2310
2311 pFS->endElement( FSNS( XML_c, nTypeId ) );
2312 }
2313}
2314
2316{
2317 sal_Int32 eChartType = getChartType( );
2318 if(eChartType == chart::TYPEID_DOUGHNUT)
2319 {
2320 exportDoughnutChart( xChartType );
2321 return;
2322 }
2323 FSHelperPtr pFS = GetFS();
2324 sal_Int32 nTypeId = XML_pieChart;
2325 if( mbIs3DChart )
2326 nTypeId = XML_pie3DChart;
2327 pFS->startElement(FSNS(XML_c, nTypeId));
2328
2329 exportVaryColors(xChartType);
2330
2331 bool bPrimaryAxes = true;
2332 exportAllSeries(xChartType, bPrimaryAxes);
2333
2334 if( !mbIs3DChart )
2335 {
2336 // firstSliceAng
2338 }
2339
2340 pFS->endElement( FSNS( XML_c, nTypeId ) );
2341}
2342
2344{
2345 FSHelperPtr pFS = GetFS();
2346 pFS->startElement(FSNS(XML_c, XML_radarChart));
2347
2348 // radarStyle
2349 sal_Int32 eChartType = getChartType( );
2350 const char* radarStyle = nullptr;
2351 if( eChartType == chart::TYPEID_RADARAREA )
2352 radarStyle = "filled";
2353 else
2354 radarStyle = "marker";
2355 pFS->singleElement(FSNS(XML_c, XML_radarStyle), XML_val, radarStyle);
2356
2357 exportVaryColors(xChartType);
2358 bool bPrimaryAxes = true;
2359 exportAllSeries(xChartType, bPrimaryAxes);
2360 exportAxesId(bPrimaryAxes);
2361
2362 pFS->endElement( FSNS( XML_c, XML_radarChart ) );
2363}
2364
2366 const css::uno::Sequence<css::uno::Reference<chart2::XDataSeries>>* pSeries)
2367{
2368 FSHelperPtr pFS = GetFS();
2369 pFS->startElement(FSNS(XML_c, XML_scatterChart));
2370 // TODO:scatterStyle
2371
2372 sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
2373 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
2374 if( GetProperty( xPropSet, "SymbolType" ) )
2375 mAny >>= nSymbolType;
2376
2377 const char* scatterStyle = "lineMarker";
2378 if (nSymbolType == css::chart::ChartSymbolType::NONE)
2379 {
2380 scatterStyle = "line";
2381 }
2382
2383 pFS->singleElement(FSNS(XML_c, XML_scatterStyle), XML_val, scatterStyle);
2384
2385 exportVaryColors(xChartType);
2386 // FIXME: should export xVal and yVal
2387 bool bPrimaryAxes = true;
2388 if (pSeries)
2389 exportSeries(xChartType, *pSeries, bPrimaryAxes);
2390 exportAxesId(bPrimaryAxes);
2391
2392 pFS->endElement( FSNS( XML_c, XML_scatterChart ) );
2393}
2394
2396{
2397 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2398 bool bExported = false;
2399 for (const auto& splitDataSeries : aSplitDataSeries)
2400 {
2401 if (!splitDataSeries.hasElements())
2402 continue;
2403
2404 bExported = true;
2405 exportScatterChartSeries(xChartType, &splitDataSeries);
2406 }
2407 if (!bExported)
2408 exportScatterChartSeries(xChartType, nullptr);
2409}
2410
2412{
2413 FSHelperPtr pFS = GetFS();
2414 const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2415 for (const auto& splitDataSeries : aSplitDataSeries)
2416 {
2417 if (!splitDataSeries.hasElements())
2418 continue;
2419
2420 pFS->startElement(FSNS(XML_c, XML_stockChart));
2421
2422 bool bPrimaryAxes = true;
2423 exportCandleStickSeries(splitDataSeries, bPrimaryAxes);
2424
2425 // export stock properties
2426 Reference< css::chart::XStatisticDisplay > xStockPropProvider(mxDiagram, uno::UNO_QUERY);
2427 if (xStockPropProvider.is())
2428 {
2430 exportUpDownBars(xChartType);
2431 }
2432
2433 exportAxesId(bPrimaryAxes);
2434
2435 pFS->endElement(FSNS(XML_c, XML_stockChart));
2436 }
2437}
2438
2440{
2441 FSHelperPtr pFS = GetFS();
2442 // export the chart property
2443 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
2444
2445 if (!xChartPropProvider.is())
2446 return;
2447
2448 Reference< beans::XPropertySet > xStockPropSet = xChartPropProvider->getMinMaxLine();
2449 if( !xStockPropSet.is() )
2450 return;
2451
2452 pFS->startElement(FSNS(XML_c, XML_hiLowLines));
2453 exportShapeProps( xStockPropSet );
2454 pFS->endElement( FSNS( XML_c, XML_hiLowLines ) );
2455}
2456
2458{
2459 if(xChartType->getChartType() != "com.sun.star.chart2.CandleStickChartType")
2460 return;
2461
2462 FSHelperPtr pFS = GetFS();
2463 // export the chart property
2464 Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
2465 if(!xChartPropProvider.is())
2466 return;
2467
2468 // updownbar
2469 pFS->startElement(FSNS(XML_c, XML_upDownBars));
2470 // TODO: gapWidth
2471 pFS->singleElement(FSNS(XML_c, XML_gapWidth), XML_val, OString::number(150));
2472
2473 Reference< beans::XPropertySet > xChartPropSet = xChartPropProvider->getUpBar();
2474 if( xChartPropSet.is() )
2475 {
2476 pFS->startElement(FSNS(XML_c, XML_upBars));
2477 // For Linechart with UpDownBars, spPr is not getting imported
2478 // so no need to call the exportShapeProps() for LineChart
2479 if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
2480 {
2481 exportShapeProps(xChartPropSet);
2482 }
2483 pFS->endElement( FSNS( XML_c, XML_upBars ) );
2484 }
2485 xChartPropSet = xChartPropProvider->getDownBar();
2486 if( xChartPropSet.is() )
2487 {
2488 pFS->startElement(FSNS(XML_c, XML_downBars));
2489 if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
2490 {
2491 exportShapeProps(xChartPropSet);
2492 }
2493 pFS->endElement( FSNS( XML_c, XML_downBars ) );
2494 }
2495 pFS->endElement( FSNS( XML_c, XML_upDownBars ) );
2496}
2497
2499{
2500 FSHelperPtr pFS = GetFS();
2501 sal_Int32 nTypeId = XML_surfaceChart;
2502 if( mbIs3DChart )
2503 nTypeId = XML_surface3DChart;
2504 pFS->startElement(FSNS(XML_c, nTypeId));
2505 exportVaryColors(xChartType);
2506 bool bPrimaryAxes = true;
2507 exportAllSeries(xChartType, bPrimaryAxes);
2508 exportAxesId(bPrimaryAxes);
2509
2510 pFS->endElement( FSNS( XML_c, nTypeId ) );
2511}
2512
2513void ChartExport::exportAllSeries(const Reference<chart2::XChartType>& xChartType, bool& rPrimaryAxes)
2514{
2515 Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
2516 if( ! xDSCnt.is())
2517 return;
2518
2519 // export dataseries for current chart-type
2520 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
2521 exportSeries(xChartType, aSeriesSeq, rPrimaryAxes);
2522}
2523
2525{
2526 FSHelperPtr pFS = GetFS();
2527 try
2528 {
2529 Reference<chart2::XDataSeries> xDataSeries = getPrimaryDataSeries(xChartType);
2530 Reference<beans::XPropertySet> xDataSeriesProps(xDataSeries, uno::UNO_QUERY_THROW);
2531 Any aAnyVaryColors = xDataSeriesProps->getPropertyValue("VaryColorsByPoint");
2532 bool bVaryColors = false;
2533 aAnyVaryColors >>= bVaryColors;
2534 pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, ToPsz10(bVaryColors));
2535 }
2536 catch (...)
2537 {
2538 pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
2539 }
2540}
2541
2543 const Sequence<Reference<chart2::XDataSeries> >& rSeriesSeq, bool& rPrimaryAxes )
2544{
2545 OUString aLabelRole = xChartType->getRoleOfSequenceForSeriesLabel();
2546 OUString aChartType( xChartType->getChartType());
2547 sal_Int32 eChartType = lcl_getChartType( aChartType );
2548
2549 for( const auto& rSeries : rSeriesSeq )
2550 {
2551 // export series
2552 Reference< chart2::data::XDataSource > xSource( rSeries, uno::UNO_QUERY );
2553 if( xSource.is())
2554 {
2555 Reference< chart2::XDataSeries > xDataSeries( xSource, uno::UNO_QUERY );
2557 xSource->getDataSequences());
2558 // search for main sequence and create a series element
2559 {
2560 sal_Int32 nMainSequenceIndex = -1;
2561 sal_Int32 nSeriesLength = 0;
2564 sal_Int32 nSeqIdx=0;
2565 for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2566 {
2567 Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2568 if( nMainSequenceIndex==-1 )
2569 {
2570 Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2571 OUString aRole;
2572 if( xSeqProp.is())
2573 xSeqProp->getPropertyValue("Role") >>= aRole;
2574 // "main" sequence
2575 if( aRole == aLabelRole )
2576 {
2577 xValuesSeq.set( xTempValueSeq );
2578 xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2579 nMainSequenceIndex = nSeqIdx;
2580 }
2581 }
2582 sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2583 if( nSeriesLength < nSequenceLength )
2584 nSeriesLength = nSequenceLength;
2585 }
2586
2587 // have found the main sequence, then xValuesSeq and
2588 // xLabelSeq contain those. Otherwise both are empty
2589 {
2590 FSHelperPtr pFS = GetFS();
2591
2592 pFS->startElement(FSNS(XML_c, XML_ser));
2593
2594 // TODO: idx and order
2595 pFS->singleElement( FSNS( XML_c, XML_idx ),
2596 XML_val, OString::number(mnSeriesCount) );
2597 pFS->singleElement( FSNS( XML_c, XML_order ),
2598 XML_val, OString::number(mnSeriesCount++) );
2599
2600 // export label
2601 if( xLabelSeq.is() )
2602 exportSeriesText( xLabelSeq );
2603
2604 Reference<XPropertySet> xPropSet(xDataSeries, UNO_QUERY_THROW);
2605 if( GetProperty( xPropSet, "AttachedAxisIndex") )
2606 {
2607 sal_Int32 nLocalAttachedAxis = 0;
2608 mAny >>= nLocalAttachedAxis;
2609 rPrimaryAxes = isPrimaryAxes(nLocalAttachedAxis);
2610 }
2611
2612 // export shape properties
2614 rSeries, getModel() );
2615 if( xOldPropSet.is() )
2616 {
2617 exportShapeProps( xOldPropSet );
2618 }
2619
2620 switch( eChartType )
2621 {
2624 case chart::TYPEID_BAR:
2625 {
2626 pFS->singleElement(FSNS(XML_c, XML_invertIfNegative), XML_val, "0");
2627 }
2628 break;
2629 case chart::TYPEID_LINE:
2630 {
2631 exportMarker(xOldPropSet);
2632 break;
2633 }
2634 case chart::TYPEID_PIE:
2636 {
2637 if( xOldPropSet.is() && GetProperty( xOldPropSet, "SegmentOffset") )
2638 {
2639 sal_Int32 nOffset = 0;
2640 mAny >>= nOffset;
2641 pFS->singleElement( FSNS( XML_c, XML_explosion ),
2642 XML_val, OString::number( nOffset ) );
2643 }
2644 break;
2645 }
2647 {
2648 exportMarker(xOldPropSet);
2649 break;
2650 }
2652 {
2653 exportMarker(xOldPropSet);
2654 break;
2655 }
2656 }
2657
2658 // export data points
2659 exportDataPoints( uno::Reference< beans::XPropertySet >( rSeries, uno::UNO_QUERY ), nSeriesLength, eChartType );
2660
2661 DataLabelsRange aDLblsRange;
2662 // export data labels
2663 exportDataLabels(rSeries, nSeriesLength, eChartType, aDLblsRange);
2664
2665 exportTrendlines( rSeries );
2666
2667 if( eChartType != chart::TYPEID_PIE &&
2668 eChartType != chart::TYPEID_RADARLINE )
2669 {
2670 //export error bars here
2671 Reference< XPropertySet > xSeriesPropSet( xSource, uno::UNO_QUERY );
2672 Reference< XPropertySet > xErrorBarYProps;
2673 xSeriesPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarYProps;
2674 if(xErrorBarYProps.is())
2675 exportErrorBar(xErrorBarYProps, true);
2676 if (eChartType != chart::TYPEID_BAR &&
2677 eChartType != chart::TYPEID_HORBAR)
2678 {
2679 Reference< XPropertySet > xErrorBarXProps;
2680 xSeriesPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarXProps;
2681 if(xErrorBarXProps.is())
2682 exportErrorBar(xErrorBarXProps, false);
2683 }
2684 }
2685
2686 // export categories
2687 if( eChartType != chart::TYPEID_SCATTER && eChartType != chart::TYPEID_BUBBLE && mxCategoriesValues.is() )
2689
2690 if( (eChartType == chart::TYPEID_SCATTER)
2691 || (eChartType == chart::TYPEID_BUBBLE) )
2692 {
2693 // export xVal
2695 if( xSequence.is() )
2696 {
2697 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2698 if( xValues.is() )
2699 exportSeriesValues( xValues, XML_xVal );
2700 }
2701 else if( mxCategoriesValues.is() )
2703 }
2704
2705 if( eChartType == chart::TYPEID_BUBBLE )
2706 {
2707 // export yVal
2709 if( xSequence.is() )
2710 {
2711 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2712 if( xValues.is() )
2713 exportSeriesValues( xValues, XML_yVal );
2714 }
2715 }
2716
2717 // export values
2718 if( xValuesSeq.is() )
2719 {
2720 sal_Int32 nYValueType = XML_val;
2721 if( eChartType == chart::TYPEID_SCATTER )
2722 nYValueType = XML_yVal;
2723 else if( eChartType == chart::TYPEID_BUBBLE )
2724 nYValueType = XML_bubbleSize;
2725 exportSeriesValues( xValuesSeq, nYValueType );
2726 }
2727
2728 if( eChartType == chart::TYPEID_SCATTER
2729 || eChartType == chart::TYPEID_LINE )
2730 exportSmooth();
2731
2732 // tdf103988: "corrupted" files with Bubble chart opening in MSO
2733 if( eChartType == chart::TYPEID_BUBBLE )
2734 pFS->singleElement(FSNS(XML_c, XML_bubble3D), XML_val, "0");
2735
2736 if (!aDLblsRange.empty())
2737 writeDataLabelsRange(pFS, GetFB(), aDLblsRange);
2738
2739 pFS->endElement( FSNS( XML_c, XML_ser ) );
2740 }
2741 }
2742 }
2743 }
2744}
2745
2747 const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
2748 bool& rPrimaryAxes)
2749{
2750 for( const Reference< chart2::XDataSeries >& xSeries : aSeriesSeq )
2751 {
2752 rPrimaryAxes = lcl_isSeriesAttachedToFirstAxis(xSeries);
2753
2754 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
2755 if( xSource.is())
2756 {
2757 // export series in correct order (as we don't store roles)
2758 // with japanese candlesticks: open, low, high, close
2759 // otherwise: low, high, close
2761 xSource->getDataSequences());
2762
2763 const char* sSeries[] = {"values-first","values-max","values-min","values-last",nullptr};
2764
2765 for( sal_Int32 idx = 0; sSeries[idx] != nullptr ; idx++ )
2766 {
2767 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii(sSeries[idx]) ) );
2768 if( xLabeledSeq.is())
2769 {
2770 Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
2771 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
2772 {
2773 FSHelperPtr pFS = GetFS();
2774 pFS->startElement(FSNS(XML_c, XML_ser));
2775
2776 // TODO: idx and order
2777 // idx attribute should start from 1 and not from 0.
2778 pFS->singleElement( FSNS( XML_c, XML_idx ),
2779 XML_val, OString::number(idx+1) );
2780 pFS->singleElement( FSNS( XML_c, XML_order ),
2781 XML_val, OString::number(idx+1) );
2782
2783 // export label
2784 if( xLabelSeq.is() )
2785 exportSeriesText( xLabelSeq );
2786
2787 // TODO:export shape properties
2788
2789 // export categories
2790 if( mxCategoriesValues.is() )
2792
2793 // export values
2794 if( xValueSeq.is() )
2795 exportSeriesValues( xValueSeq );
2796
2797 pFS->endElement( FSNS( XML_c, XML_ser ) );
2798 }
2799 }
2800 }
2801 }
2802 }
2803}
2804
2806{
2807 FSHelperPtr pFS = GetFS();
2808 pFS->startElement(FSNS(XML_c, XML_tx));
2809
2810 OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
2811 aCellRange = parseFormula( aCellRange );
2812 pFS->startElement(FSNS(XML_c, XML_strRef));
2813
2814 pFS->startElement(FSNS(XML_c, XML_f));
2815 pFS->writeEscaped( aCellRange );
2816 pFS->endElement( FSNS( XML_c, XML_f ) );
2817
2818 OUString aLabelString = lcl_flattenStringSequence(lcl_getLabelSequence(xValueSeq));
2819 pFS->startElement(FSNS(XML_c, XML_strCache));
2820 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, "1");
2821 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, "0");
2822 pFS->startElement(FSNS(XML_c, XML_v));
2823 pFS->writeEscaped( aLabelString );
2824 pFS->endElement( FSNS( XML_c, XML_v ) );
2825 pFS->endElement( FSNS( XML_c, XML_pt ) );
2826 pFS->endElement( FSNS( XML_c, XML_strCache ) );
2827 pFS->endElement( FSNS( XML_c, XML_strRef ) );
2828 pFS->endElement( FSNS( XML_c, XML_tx ) );
2829}
2830
2832{
2833 FSHelperPtr pFS = GetFS();
2834 pFS->startElement(FSNS(XML_c, nValueType));
2835
2836 OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2837 const Sequence< Sequence< OUString >> aFinalSplitSource = (nValueType == XML_cat) ? getSplitCategoriesList(aCellRange) : Sequence< Sequence< OUString>>(0);
2838 aCellRange = parseFormula( aCellRange );
2839
2840 if(aFinalSplitSource.getLength() > 1)
2841 {
2842 // export multi level category axis labels
2843 pFS->startElement(FSNS(XML_c, XML_multiLvlStrRef));
2844
2845 pFS->startElement(FSNS(XML_c, XML_f));
2846 pFS->writeEscaped(aCellRange);
2847 pFS->endElement(FSNS(XML_c, XML_f));
2848
2849 pFS->startElement(FSNS(XML_c, XML_multiLvlStrCache));
2850 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(aFinalSplitSource[0].getLength()));
2851 for(const auto& rSeq : aFinalSplitSource)
2852 {
2853 pFS->startElement(FSNS(XML_c, XML_lvl));
2854 for(sal_Int32 j = 0; j < rSeq.getLength(); j++)
2855 {
2856 if(!rSeq[j].isEmpty())
2857 {
2858 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(j));
2859 pFS->startElement(FSNS(XML_c, XML_v));
2860 pFS->writeEscaped(rSeq[j]);
2861 pFS->endElement(FSNS(XML_c, XML_v));
2862 pFS->endElement(FSNS(XML_c, XML_pt));
2863 }
2864 }
2865 pFS->endElement(FSNS(XML_c, XML_lvl));
2866 }
2867
2868 pFS->endElement(FSNS(XML_c, XML_multiLvlStrCache));
2869 pFS->endElement(FSNS(XML_c, XML_multiLvlStrRef));
2870 }
2871 else
2872 {
2873 // export single category axis labels
2874 bool bWriteDateCategories = mbHasDateCategories && (nValueType == XML_cat);
2875 OUString aNumberFormatString;
2876 if (bWriteDateCategories)
2877 {
2878 Reference< css::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
2879 if( xAxisXSupp.is())
2880 {
2881 Reference< XPropertySet > xAxisProp = xAxisXSupp->getXAxis();
2882 if (GetProperty(xAxisProp, "NumberFormat"))
2883 {
2884 sal_Int32 nKey = 0;
2885 mAny >>= nKey;
2886 aNumberFormatString = getNumberFormatCode(nKey);
2887 }
2888 }
2889 if (aNumberFormatString.isEmpty())
2890 bWriteDateCategories = false;
2891 }
2892
2893 pFS->startElement(FSNS(XML_c, bWriteDateCategories ? XML_numRef : XML_strRef));
2894
2895 pFS->startElement(FSNS(XML_c, XML_f));
2896 pFS->writeEscaped(aCellRange);
2897 pFS->endElement(FSNS(XML_c, XML_f));
2898
2899 ::std::vector< OUString > aCategories;
2900 lcl_fillCategoriesIntoStringVector(xValueSeq, aCategories);
2901 sal_Int32 ptCount = aCategories.size();
2902 pFS->startElement(FSNS(XML_c, bWriteDateCategories ? XML_numCache : XML_strCache));
2903 if (bWriteDateCategories)
2904 {
2905 pFS->startElement(FSNS(XML_c, XML_formatCode));
2906 pFS->writeEscaped(aNumberFormatString);
2907 pFS->endElement(FSNS(XML_c, XML_formatCode));
2908 }
2909
2910 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(ptCount));
2911 for (sal_Int32 i = 0; i < ptCount; i++)
2912 {
2913 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(i));
2914 pFS->startElement(FSNS(XML_c, XML_v));
2915 pFS->writeEscaped(aCategories[i]);
2916 pFS->endElement(FSNS(XML_c, XML_v));
2917 pFS->endElement(FSNS(XML_c, XML_pt));
2918 }
2919
2920 pFS->endElement(FSNS(XML_c, bWriteDateCategories ? XML_numCache : XML_strCache));
2921 pFS->endElement(FSNS(XML_c, bWriteDateCategories ? XML_numRef : XML_strRef));
2922 }
2923
2924 pFS->endElement( FSNS( XML_c, nValueType ) );
2925}
2926
2928{
2929 FSHelperPtr pFS = GetFS();
2930 pFS->startElement(FSNS(XML_c, nValueType));
2931
2932 OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2933 aCellRange = parseFormula( aCellRange );
2934 // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2935 pFS->startElement(FSNS(XML_c, XML_numRef));
2936
2937 pFS->startElement(FSNS(XML_c, XML_f));
2938 pFS->writeEscaped( aCellRange );
2939 pFS->endElement( FSNS( XML_c, XML_f ) );
2940
2941 ::std::vector< double > aValues = lcl_getAllValuesFromSequence( xValueSeq );
2942 sal_Int32 ptCount = aValues.size();
2943 pFS->startElement(FSNS(XML_c, XML_numCache));
2944 pFS->startElement(FSNS(XML_c, XML_formatCode));
2945 // TODO: what format code?
2946 pFS->writeEscaped( "General" );
2947 pFS->endElement( FSNS( XML_c, XML_formatCode ) );
2948 pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(ptCount));
2949
2950 for( sal_Int32 i = 0; i < ptCount; i++ )
2951 {
2952 if (!std::isnan(aValues[i]))
2953 {
2954 pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(i));
2955 pFS->startElement(FSNS(XML_c, XML_v));
2956 pFS->write(aValues[i]);
2957 pFS->endElement(FSNS(XML_c, XML_v));
2958 pFS->endElement(FSNS(XML_c, XML_pt));
2959 }
2960 }
2961
2962 pFS->endElement( FSNS( XML_c, XML_numCache ) );
2963 pFS->endElement( FSNS( XML_c, XML_numRef ) );
2964 pFS->endElement( FSNS( XML_c, nValueType ) );
2965}
2966
2968{
2969 FSHelperPtr pFS = GetFS();
2970 pFS->startElement(FSNS(XML_c, XML_spPr));
2971
2972 exportFill( xPropSet );
2973 WriteOutline( xPropSet, getModel() );
2974
2975 pFS->endElement( FSNS( XML_c, XML_spPr ) );
2976}
2977
2979{
2980 FSHelperPtr pFS = GetFS();
2981 pFS->startElement(FSNS(XML_c, XML_txPr));
2982
2983 sal_Int32 nRotation = 0;
2984 const char* textWordWrap = nullptr;
2985
2986 if (auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xPropSet, uno::UNO_QUERY))
2987 {
2988 double fMultiplier = 0.0;
2989 // We have at least two possible units of returned value: degrees (e.g., for data labels),
2990 // and 100ths of degree (e.g., for axes labels). The latter is returned as an Any wrapping
2991 // a sal_Int32 value (see WrappedTextRotationProperty::convertInnerToOuterValue), while
2992 // the former is double. So we could test the contained type to decide which multiplier to
2993 // use. But testing the service info should be more robust.
2994 if (xServiceInfo->supportsService("com.sun.star.chart.ChartAxis"))
2995 fMultiplier = -600.0;
2996 else if (xServiceInfo->supportsService("com.sun.star.chart2.DataSeries") || xServiceInfo->supportsService("com.sun.star.chart2.DataPointProperties"))
2997 {
2998 fMultiplier = -60000.0;
2999 bool bTextWordWrap = false;
3000 if ((xPropSet->getPropertyValue("TextWordWrap") >>= bTextWordWrap) && bTextWordWrap)
3001 textWordWrap = "square";
3002 else
3003 textWordWrap = "none";
3004 }
3005
3006 if (fMultiplier)
3007 {
3008 double fTextRotation = 0.0;
3009 uno::Any aAny = xPropSet->getPropertyValue("TextRotation");
3010 if (aAny.hasValue() && (aAny >>= fTextRotation))
3011 {
3012 fTextRotation *= fMultiplier;
3013 // The MS Office UI allows values only in range of [-90,90].
3014 if (fTextRotation < -5400000.0 && fTextRotation > -16200000.0)
3015 {
3016 // Reflect the angle if the value is between 90° and 270°
3017 fTextRotation += 10800000.0;
3018 }
3019 else if (fTextRotation <= -16200000.0)
3020 {
3021 fTextRotation += 21600000.0;
3022 }
3023 nRotation = std::round(fTextRotation);
3024 }
3025 }
3026 }
3027
3028 if (nRotation)
3029 pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_rot, OString::number(nRotation), XML_wrap, textWordWrap);
3030 else
3031 pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_wrap, textWordWrap);
3032
3033 pFS->singleElement(FSNS(XML_a, XML_lstStyle));
3034
3035 pFS->startElement(FSNS(XML_a, XML_p));
3036 pFS->startElement(FSNS(XML_a, XML_pPr));
3037
3038 WriteRunProperties(xPropSet, false, XML_defRPr, true, o3tl::temporary(false),
3039 o3tl::temporary(sal_Int32()));
3040
3041 pFS->endElement(FSNS(XML_a, XML_pPr));
3042 pFS->endElement(FSNS(XML_a, XML_p));
3043 pFS->endElement(FSNS(XML_c, XML_txPr));
3044}
3045
3047{
3048 Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
3049
3050 // Check for supported services and then the properties provided by this service.
3051 Reference<lang::XServiceInfo> xServiceInfo (mxDiagram, uno::UNO_QUERY);
3052 if (xServiceInfo.is())
3053 {
3054 if (xServiceInfo->supportsService("com.sun.star.chart.ChartAxisZSupplier"))
3055 {
3056 xDiagramProperties->getPropertyValue("HasZAxis") >>= mbHasZAxis;
3057 }
3058 }
3059
3060 xDiagramProperties->getPropertyValue("Dim3D") >>= mbIs3DChart;
3061
3063 {
3065 if( xCategories.is() )
3066 {
3067 mxCategoriesValues.set( xCategories->getValues() );
3068 }
3069 }
3070}
3071
3073{
3074 sal_Int32 nSize = maAxes.size();
3075 // let's export the axis types in the right order
3076 for ( sal_Int32 nSortIdx = AXIS_PRIMARY_X; nSortIdx <= AXIS_SECONDARY_Y; nSortIdx++ )
3077 {
3078 for ( sal_Int32 nIdx = 0; nIdx < nSize; nIdx++ )
3079 {
3080 if (nSortIdx == maAxes[nIdx].nAxisType)
3081 exportAxis( maAxes[nIdx] );
3082 }
3083 }
3084}
3085
3086namespace {
3087
3088sal_Int32 getXAxisTypeByChartType(sal_Int32 eChartType)
3089{
3090 if( (eChartType == chart::TYPEID_SCATTER)
3091 || (eChartType == chart::TYPEID_BUBBLE) )
3092 return XML_valAx;
3093 else if( eChartType == chart::TYPEID_STOCK )
3094 return XML_dateAx;
3095
3096 return XML_catAx;
3097}
3098
3099sal_Int32 getRealXAxisType(sal_Int32 nAxisType)
3100{
3101 if( nAxisType == chart2::AxisType::CATEGORY )
3102 return XML_catAx;
3103 else if( nAxisType == chart2::AxisType::DATE )
3104 return XML_dateAx;
3105 else if( nAxisType == chart2::AxisType::SERIES )
3106 return XML_serAx;
3107
3108 return XML_valAx;
3109}
3110
3111}
3112
3113void ChartExport::exportAxis(const AxisIdPair& rAxisIdPair)
3114{
3115 // get some properties from document first
3116 bool bHasXAxisTitle = false,
3117 bHasYAxisTitle = false,
3118 bHasZAxisTitle = false,
3119 bHasSecondaryXAxisTitle = false,
3120 bHasSecondaryYAxisTitle = false;
3121 bool bHasXAxisMajorGrid = false,
3122 bHasXAxisMinorGrid = false,
3123 bHasYAxisMajorGrid = false,
3124 bHasYAxisMinorGrid = false,
3125 bHasZAxisMajorGrid = false,
3126 bHasZAxisMinorGrid = false;
3127
3128 Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
3129
3130 xDiagramProperties->getPropertyValue("HasXAxisTitle") >>= bHasXAxisTitle;
3131 xDiagramProperties->getPropertyValue("HasYAxisTitle") >>= bHasYAxisTitle;
3132 xDiagramProperties->getPropertyValue("HasZAxisTitle") >>= bHasZAxisTitle;
3133 xDiagramProperties->getPropertyValue("HasSecondaryXAxisTitle") >>= bHasSecondaryXAxisTitle;
3134 xDiagramProperties->getPropertyValue("HasSecondaryYAxisTitle") >>= bHasSecondaryYAxisTitle;
3135
3136 xDiagramProperties->getPropertyValue("HasXAxisGrid") >>= bHasXAxisMajorGrid;
3137 xDiagramProperties->getPropertyValue("HasYAxisGrid") >>= bHasYAxisMajorGrid;
3138 xDiagramProperties->getPropertyValue("HasZAxisGrid") >>= bHasZAxisMajorGrid;
3139
3140 xDiagramProperties->getPropertyValue("HasXAxisHelpGrid") >>= bHasXAxisMinorGrid;
3141 xDiagramProperties->getPropertyValue("HasYAxisHelpGrid") >>= bHasYAxisMinorGrid;
3142 xDiagramProperties->getPropertyValue("HasZAxisHelpGrid") >>= bHasZAxisMinorGrid;
3143
3144 Reference< XPropertySet > xAxisProp;
3148 sal_Int32 nAxisType = XML_catAx;
3149 const char* sAxPos = nullptr;
3150
3151 switch( rAxisIdPair.nAxisType )
3152 {
3153 case AXIS_PRIMARY_X:
3154 {
3155 Reference< css::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
3156 if( xAxisXSupp.is())
3157 xAxisProp = xAxisXSupp->getXAxis();
3158 if( bHasXAxisTitle )
3159 xAxisTitle = xAxisXSupp->getXAxisTitle();
3160 if( bHasXAxisMajorGrid )
3161 xMajorGrid = xAxisXSupp->getXMainGrid();
3162 if( bHasXAxisMinorGrid )
3163 xMinorGrid = xAxisXSupp->getXHelpGrid();
3164
3165 nAxisType = lcl_getCategoryAxisType(mxNewDiagram, 0, 0);
3166 if( nAxisType != -1 )
3167 nAxisType = getRealXAxisType(nAxisType);
3168 else
3169 nAxisType = getXAxisTypeByChartType( getChartType() );
3170 // FIXME: axPos, need to check axis direction
3171 sAxPos = "b";
3172 break;
3173 }
3174 case AXIS_PRIMARY_Y:
3175 {
3176 Reference< css::chart::XAxisYSupplier > xAxisYSupp( mxDiagram, uno::UNO_QUERY );
3177 if( xAxisYSupp.is())
3178 xAxisProp = xAxisYSupp->getYAxis();
3179 if( bHasYAxisTitle )
3180 xAxisTitle = xAxisYSupp->getYAxisTitle();
3181 if( bHasYAxisMajorGrid )
3182 xMajorGrid = xAxisYSupp->getYMainGrid();
3183 if( bHasYAxisMinorGrid )
3184 xMinorGrid = xAxisYSupp->getYHelpGrid();
3185
3186 nAxisType = XML_valAx;
3187 // FIXME: axPos, need to check axis direction
3188 sAxPos = "l";
3189 break;
3190 }
3191 case AXIS_PRIMARY_Z:
3192 {
3193 Reference< css::chart::XAxisZSupplier > xAxisZSupp( mxDiagram, uno::UNO_QUERY );
3194 if( xAxisZSupp.is())
3195 xAxisProp = xAxisZSupp->getZAxis();
3196 if( bHasZAxisTitle )
3197 xAxisTitle = xAxisZSupp->getZAxisTitle();
3198 if( bHasZAxisMajorGrid )
3199 xMajorGrid = xAxisZSupp->getZMainGrid();
3200 if( bHasZAxisMinorGrid )
3201 xMinorGrid = xAxisZSupp->getZHelpGrid();
3202
3203 sal_Int32 eChartType = getChartType( );
3204 if( (eChartType == chart::TYPEID_SCATTER)
3205 || (eChartType == chart::TYPEID_BUBBLE) )
3206 nAxisType = XML_valAx;
3207 else if( eChartType == chart::TYPEID_STOCK )
3208 nAxisType = XML_dateAx;
3209 else if( eChartType == chart::TYPEID_BAR || eChartType == chart::TYPEID_AREA )
3210 nAxisType = XML_serAx;
3211 // FIXME: axPos, need to check axis direction
3212 sAxPos = "b";
3213 break;
3214 }
3215 case AXIS_SECONDARY_X:
3216 {
3217 Reference< css::chart::XTwoAxisXSupplier > xAxisTwoXSupp( mxDiagram, uno::UNO_QUERY );
3218 if( xAxisTwoXSupp.is())
3219 xAxisProp = xAxisTwoXSupp->getSecondaryXAxis();
3220 if( bHasSecondaryXAxisTitle )
3221 {
3223 xAxisTitle = xAxisSupp->getSecondXAxisTitle();
3224 }
3225
3226 nAxisType = lcl_getCategoryAxisType(mxNewDiagram, 0, 1);
3227 if( nAxisType != -1 )
3228 nAxisType = getRealXAxisType(nAxisType);
3229 else
3230 nAxisType = getXAxisTypeByChartType( getChartType() );
3231 // FIXME: axPos, need to check axis direction
3232 sAxPos = "t";
3233 break;
3234 }
3235 case AXIS_SECONDARY_Y:
3236 {
3237 Reference< css::chart::XTwoAxisYSupplier > xAxisTwoYSupp( mxDiagram, uno::UNO_QUERY );
3238 if( xAxisTwoYSupp.is())
3239 xAxisProp = xAxisTwoYSupp->getSecondaryYAxis();
3240 if( bHasSecondaryYAxisTitle )
3241 {
3243 xAxisTitle = xAxisSupp->getSecondYAxisTitle();
3244 }
3245
3246 nAxisType = XML_valAx;
3247 // FIXME: axPos, need to check axis direction
3248 sAxPos = "r";
3249 break;
3250 }
3251 }
3252
3253 _exportAxis(xAxisProp, xAxisTitle, xMajorGrid, xMinorGrid, nAxisType, sAxPos, rAxisIdPair);
3254}
3255
3257 const Reference< XPropertySet >& xAxisProp,
3258 const Reference< drawing::XShape >& xAxisTitle,
3259 const Reference< XPropertySet >& xMajorGrid,
3260 const Reference< XPropertySet >& xMinorGrid,
3261 sal_Int32 nAxisType,
3262 const char* sAxisPos,
3263 const AxisIdPair& rAxisIdPair )
3264{
3265 FSHelperPtr pFS = GetFS();
3266 pFS->startElement(FSNS(XML_c, nAxisType));
3267 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(rAxisIdPair.nAxisId));
3268
3269 pFS->startElement(FSNS(XML_c, XML_scaling));
3270
3271 // logBase, min, max
3272 if(GetProperty( xAxisProp, "Logarithmic" ) )
3273 {
3274 bool bLogarithmic = false;
3275 mAny >>= bLogarithmic;
3276 if( bLogarithmic )
3277 {
3278 // default value is 10?
3279 pFS->singleElement(FSNS(XML_c, XML_logBase), XML_val, OString::number(10));
3280 }
3281 }
3282
3283 // orientation: minMax, maxMin
3284 bool bReverseDirection = false;
3285 if(GetProperty( xAxisProp, "ReverseDirection" ) )
3286 mAny >>= bReverseDirection;
3287
3288 const char* orientation = bReverseDirection ? "maxMin":"minMax";
3289 pFS->singleElement(FSNS(XML_c, XML_orientation), XML_val, orientation);
3290
3291 bool bAutoMax = false;
3292 if(GetProperty( xAxisProp, "AutoMax" ) )
3293 mAny >>= bAutoMax;
3294
3295 if( !bAutoMax && (GetProperty( xAxisProp, "Max" ) ) )
3296 {
3297 double dMax = 0;
3298 mAny >>= dMax;
3299 pFS->singleElement(FSNS(XML_c, XML_max), XML_val, OString::number(dMax));
3300 }
3301
3302 bool bAutoMin = false;
3303 if(GetProperty( xAxisProp, "AutoMin" ) )
3304 mAny >>= bAutoMin;
3305
3306 if( !bAutoMin && (GetProperty( xAxisProp, "Min" ) ) )
3307 {
3308 double dMin = 0;
3309 mAny >>= dMin;
3310 pFS->singleElement(FSNS(XML_c, XML_min), XML_val, OString::number(dMin));
3311 }
3312
3313 pFS->endElement( FSNS( XML_c, XML_scaling ) );
3314
3315 bool bVisible = true;
3316 if( xAxisProp.is() )
3317 {
3318 xAxisProp->getPropertyValue("Visible") >>= bVisible;
3319 }
3320
3321 // only export each axis only once non-deleted
3322 bool bDeleted = maExportedAxis.find(rAxisIdPair.nAxisType) != maExportedAxis.end();
3323
3324 if (!bDeleted)
3325 maExportedAxis.insert(rAxisIdPair.nAxisType);
3326
3327 pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, !bDeleted && bVisible ? "0" : "1");
3328
3329 // FIXME: axPos, need to check the property "ReverseDirection"
3330 pFS->singleElement(FSNS(XML_c, XML_axPos), XML_val, sAxisPos);
3331 // major grid line
3332 if( xMajorGrid.is())
3333 {
3334 pFS->startElement(FSNS(XML_c, XML_majorGridlines));
3335 exportShapeProps( xMajorGrid );
3336 pFS->endElement( FSNS( XML_c, XML_majorGridlines ) );
3337 }
3338
3339 // minor grid line
3340 if( xMinorGrid.is())
3341 {
3342 pFS->startElement(FSNS(XML_c, XML_minorGridlines));
3343 exportShapeProps( xMinorGrid );
3344 pFS->endElement( FSNS( XML_c, XML_minorGridlines ) );
3345 }
3346
3347 // title
3348 if( xAxisTitle.is() )
3349 exportTitle( xAxisTitle );
3350
3351 bool bLinkedNumFmt = true;
3352 if (GetProperty(xAxisProp, "LinkNumberFormatToSource"))
3353 mAny >>= bLinkedNumFmt;
3354
3355 OUString aNumberFormatString("General");
3356 if (GetProperty(xAxisProp, "NumberFormat"))
3357 {
3358 sal_Int32 nKey = 0;
3359 mAny >>= nKey;
3360 aNumberFormatString = getNumberFormatCode(nKey);
3361 }
3362
3363 pFS->singleElement(FSNS(XML_c, XML_numFmt),
3364 XML_formatCode, aNumberFormatString,
3365 XML_sourceLinked, bLinkedNumFmt ? "1" : "0");
3366
3367 // majorTickMark
3368 sal_Int32 nValue = 0;
3369 if(GetProperty( xAxisProp, "Marks" ) )
3370 {
3371 mAny >>= nValue;
3372 bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
3373 bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
3374 const char* majorTickMark = nullptr;
3375 if( bInner && bOuter )
3376 majorTickMark = "cross";
3377 else if( bInner )
3378 majorTickMark = "in";
3379 else if( bOuter )
3380 majorTickMark = "out";
3381 else
3382 majorTickMark = "none";
3383 pFS->singleElement(FSNS(XML_c, XML_majorTickMark), XML_val, majorTickMark);
3384 }
3385 // minorTickMark
3386 if(GetProperty( xAxisProp, "HelpMarks" ) )
3387 {
3388 mAny >>= nValue;
3389 bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
3390 bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
3391 const char* minorTickMark = nullptr;
3392 if( bInner && bOuter )
3393 minorTickMark = "cross";
3394 else if( bInner )
3395 minorTickMark = "in";
3396 else if( bOuter )
3397 minorTickMark = "out";
3398 else
3399 minorTickMark = "none";
3400 pFS->singleElement(FSNS(XML_c, XML_minorTickMark), XML_val, minorTickMark);
3401 }
3402 // tickLblPos
3403 const char* sTickLblPos = nullptr;
3404 bool bDisplayLabel = true;
3405 if(GetProperty( xAxisProp, "DisplayLabels" ) )
3406 mAny >>= bDisplayLabel;
3407 if( bDisplayLabel && (GetProperty( xAxisProp, "LabelPosition" ) ) )
3408 {
3409 css::chart::ChartAxisLabelPosition eLabelPosition = css::chart::ChartAxisLabelPosition_NEAR_AXIS;
3410 mAny >>= eLabelPosition;
3411 switch( eLabelPosition )
3412 {
3413 case css::chart::ChartAxisLabelPosition_NEAR_AXIS:
3414 case css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE:
3415 sTickLblPos = "nextTo";
3416 break;
3417 case css::chart::ChartAxisLabelPosition_OUTSIDE_START:
3418 sTickLblPos = "low";
3419 break;
3420 case css::chart::ChartAxisLabelPosition_OUTSIDE_END:
3421 sTickLblPos = "high";
3422 break;
3423 default:
3424 sTickLblPos = "nextTo";
3425 break;
3426 }
3427 }
3428 else
3429 {
3430 sTickLblPos = "none";
3431 }
3432 pFS->singleElement(FSNS(XML_c, XML_tickLblPos), XML_val, sTickLblPos);
3433
3434 // shape properties
3435 exportShapeProps( xAxisProp );
3436
3437 exportTextProps(xAxisProp);
3438
3439 pFS->singleElement(FSNS(XML_c, XML_crossAx), XML_val, OString::number(rAxisIdPair.nCrossAx));
3440
3441 // crosses & crossesAt
3442 bool bCrossesValue = false;
3443 const char* sCrosses = nullptr;
3444 // do not export the CrossoverPosition/CrossoverValue, if the axis is deleted and not visible
3445 if( GetProperty( xAxisProp, "CrossoverPosition" ) && !bDeleted && bVisible )
3446 {
3447 css::chart::ChartAxisPosition ePosition( css::chart::ChartAxisPosition_ZERO );
3448 mAny >>= ePosition;
3449 switch( ePosition )
3450 {
3451 case css::chart::ChartAxisPosition_START:
3452 sCrosses = "min";
3453 break;
3454 case css::chart::ChartAxisPosition_END:
3455 sCrosses = "max";
3456 break;
3457 case css::chart::ChartAxisPosition_ZERO:
3458 sCrosses = "autoZero";
3459 break;
3460 default:
3461 bCrossesValue = true;
3462 break;
3463 }
3464 }
3465
3466 if( bCrossesValue && GetProperty( xAxisProp, "CrossoverValue" ) )
3467 {
3468 double dValue = 0;
3469 mAny >>= dValue;
3470 pFS->singleElement(FSNS(XML_c, XML_crossesAt), XML_val, OString::number(dValue));
3471 }
3472 else
3473 {
3474 if(sCrosses)
3475 {
3476 pFS->singleElement(FSNS(XML_c, XML_crosses), XML_val, sCrosses);
3477 }
3478 }
3479
3480 if( ( nAxisType == XML_catAx )
3481 || ( nAxisType == XML_dateAx ) )
3482 {
3483 // FIXME: seems not support? use default value,
3484 const char* const isAuto = "1";
3485 pFS->singleElement(FSNS(XML_c, XML_auto), XML_val, isAuto);
3486
3487 if( nAxisType == XML_catAx )
3488 {
3489 // FIXME: seems not support? lblAlgn
3490 const char* const sLblAlgn = "ctr";
3491 pFS->singleElement(FSNS(XML_c, XML_lblAlgn), XML_val, sLblAlgn);
3492 }
3493
3494 // FIXME: seems not support? lblOffset
3495 pFS->singleElement(FSNS(XML_c, XML_lblOffset), XML_val, OString::number(100));
3496
3497 // export baseTimeUnit, majorTimeUnit, minorTimeUnit of Date axis
3498 if( nAxisType == XML_dateAx )
3499 {
3500 sal_Int32 nAxisIndex = -1;
3501 if( rAxisIdPair.nAxisType == AXIS_PRIMARY_X )
3502 nAxisIndex = 0;
3503 else if( rAxisIdPair.nAxisType == AXIS_SECONDARY_X )
3504 nAxisIndex = 1;
3505
3506 cssc::TimeIncrement aTimeIncrement = lcl_getDateTimeIncrement( mxNewDiagram, nAxisIndex );
3507 sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY;
3508 if( aTimeIncrement.TimeResolution >>= nTimeResolution )
3509 pFS->singleElement(FSNS(XML_c, XML_baseTimeUnit), XML_val, lclGetTimeUnitToken(nTimeResolution));
3510
3511 cssc::TimeInterval aInterval;
3512 if( aTimeIncrement.MajorTimeInterval >>= aInterval )
3513 {
3514 pFS->singleElement(FSNS(XML_c, XML_majorUnit), XML_val, OString::number(aInterval.Number));
3515 pFS->singleElement(FSNS(XML_c, XML_majorTimeUnit), XML_val, lclGetTimeUnitToken(aInterval.TimeUnit));
3516 }
3517 if( aTimeIncrement.MinorTimeInterval >>= aInterval )
3518 {
3519 pFS->singleElement(FSNS(XML_c, XML_minorUnit), XML_val, OString::number(aInterval.Number));
3520 pFS->singleElement(FSNS(XML_c, XML_minorTimeUnit), XML_val, lclGetTimeUnitToken(aInterval.TimeUnit));
3521 }
3522 }
3523
3524 // FIXME: seems not support? noMultiLvlLbl
3525 pFS->singleElement(FSNS(XML_c, XML_noMultiLvlLbl), XML_val, OString::number(0));
3526 }
3527
3528 // crossBetween
3529 if( nAxisType == XML_valAx )
3530 {
3532 pFS->singleElement(FSNS(XML_c, XML_crossBetween), XML_val, "between");
3533 else
3534 pFS->singleElement(FSNS(XML_c, XML_crossBetween), XML_val, "midCat");
3535 }
3536
3537 // majorUnit
3538 bool bAutoStepMain = false;
3539 if(GetProperty( xAxisProp, "AutoStepMain" ) )
3540 mAny >>= bAutoStepMain;
3541
3542 if( !bAutoStepMain && (GetProperty( xAxisProp, "StepMain" ) ) )
3543 {
3544 double dMajorUnit = 0;
3545 mAny >>= dMajorUnit;
3546 pFS->singleElement(FSNS(XML_c, XML_majorUnit), XML_val, OString::number(dMajorUnit));
3547 }
3548 // minorUnit
3549 bool bAutoStepHelp = false;
3550 if(GetProperty( xAxisProp, "AutoStepHelp" ) )
3551 mAny >>= bAutoStepHelp;
3552
3553 if( !bAutoStepHelp && (GetProperty( xAxisProp, "StepHelp" ) ) )
3554 {
3555 double dMinorUnit = 0;
3556 mAny >>= dMinorUnit;
3557 if( GetProperty( xAxisProp, "StepHelpCount" ) )
3558 {
3559 sal_Int32 dMinorUnitCount = 0;
3560 mAny >>= dMinorUnitCount;
3561 // tdf#114168 Don't save minor unit if number of step help count is 5 (which is default for MS Excel),
3562 // to allow proper .xlsx import. If minorUnit is set and majorUnit not, then it is impossible
3563 // to calculate StepHelpCount.
3564 if( dMinorUnitCount != 5 )
3565 {
3566 pFS->singleElement( FSNS( XML_c, XML_minorUnit ),
3567 XML_val, OString::number( dMinorUnit ) );
3568 }
3569 }
3570 }
3571
3572 if( nAxisType == XML_valAx && GetProperty( xAxisProp, "DisplayUnits" ) )
3573 {
3574 bool bDisplayUnits = false;
3575 mAny >>= bDisplayUnits;
3576 if(bDisplayUnits)
3577 {
3578 if(GetProperty( xAxisProp, "BuiltInUnit" ))
3579 {
3580 OUString aVal;
3581 mAny >>= aVal;
3582 if(!aVal.isEmpty())
3583 {
3584 pFS->startElement(FSNS(XML_c, XML_dispUnits));
3585
3586 pFS->singleElement(FSNS(XML_c, XML_builtInUnit), XML_val, aVal);
3587
3588 pFS->singleElement(FSNS( XML_c, XML_dispUnitsLbl ));
3589 pFS->endElement( FSNS( XML_c, XML_dispUnits ) );
3590 }
3591 }
3592 }
3593 }
3594
3595 pFS->endElement( FSNS( XML_c, nAxisType ) );
3596}
3597
3598namespace {
3599
3600struct LabelPlacementParam
3601{
3603 sal_Int32 meDefault;
3604
3605 std::unordered_set<sal_Int32> maAllowedValues;
3606
3607 LabelPlacementParam(bool bExport, sal_Int32 nDefault) :
3608 mbExport(bExport),
3609 meDefault(nDefault),
3611 {
3612 css::chart::DataLabelPlacement::OUTSIDE,
3613 css::chart::DataLabelPlacement::INSIDE,
3614 css::chart::DataLabelPlacement::CENTER,
3615 css::chart::DataLabelPlacement::NEAR_ORIGIN,
3616 css::chart::DataLabelPlacement::TOP,
3617 css::chart::DataLabelPlacement::BOTTOM,
3618 css::chart::DataLabelPlacement::LEFT,
3619 css::chart::DataLabelPlacement::RIGHT,
3620 css::chart::DataLabelPlacement::AVOID_OVERLAP
3621 }
3622 )
3623 {}
3624};
3625
3626const char* toOOXMLPlacement( sal_Int32 nPlacement )
3627{
3628 switch (nPlacement)
3629 {
3630 case css::chart::DataLabelPlacement::OUTSIDE: return "outEnd";
3631 case css::chart::DataLabelPlacement::INSIDE: return "inEnd";
3632 case css::chart::DataLabelPlacement::CENTER: return "ctr";
3633 case css::chart::DataLabelPlacement::NEAR_ORIGIN: return "inBase";
3634 case css::chart::DataLabelPlacement::TOP: return "t";
3635 case css::chart::DataLabelPlacement::BOTTOM: return "b";
3636 case css::chart::DataLabelPlacement::LEFT: return "l";
3637 case css::chart::DataLabelPlacement::RIGHT: return "r";
3638 case css::chart::DataLabelPlacement::CUSTOM:
3639 case css::chart::DataLabelPlacement::AVOID_OVERLAP: return "bestFit";
3640 default:
3641 ;
3642 }
3643
3644 return "outEnd";
3645}
3646
3647OUString getFieldTypeString( const chart2::DataPointCustomLabelFieldType aType )
3648{
3649 switch (aType)
3650 {
3651 case chart2::DataPointCustomLabelFieldType_CATEGORYNAME:
3652 return "CATEGORYNAME";
3653
3654 case chart2::DataPointCustomLabelFieldType_SERIESNAME:
3655 return "SERIESNAME";
3656
3657 case chart2::DataPointCustomLabelFieldType_VALUE:
3658 return "VALUE";
3659
3660 case chart2::DataPointCustomLabelFieldType_CELLREF:
3661 return "CELLREF";
3662
3663 case chart2::DataPointCustomLabelFieldType_CELLRANGE:
3664 return "CELLRANGE";
3665
3666 default:
3667 break;
3668 }
3669 return OUString();
3670}
3671
3672void writeRunProperties( ChartExport* pChartExport, Reference<XPropertySet> const & xPropertySet )
3673{
3674 bool bDummy = false;
3675 sal_Int32 nDummy;
3676 pChartExport->WriteRunProperties(xPropertySet, false, XML_rPr, true, bDummy, nDummy);
3677}
3678
3679void writeCustomLabel( const FSHelperPtr& pFS, ChartExport* pChartExport,
3680 const Sequence<Reference<chart2::XDataPointCustomLabelField>>& rCustomLabelFields,
3681 sal_Int32 nLabelIndex, DataLabelsRange& rDLblsRange )
3682{
3683 pFS->startElement(FSNS(XML_c, XML_tx));
3684 pFS->startElement(FSNS(XML_c, XML_rich));
3685
3686 // TODO: body properties?
3687 pFS->singleElement(FSNS(XML_a, XML_bodyPr));
3688
3689 OUString sFieldType;
3690 OUString sContent;
3691 pFS->startElement(FSNS(XML_a, XML_p));
3692
3693 for (auto& rField : rCustomLabelFields)
3694 {
3695 Reference<XPropertySet> xPropertySet(rField, UNO_QUERY);
3696 chart2::DataPointCustomLabelFieldType aType = rField->getFieldType();
3697 sFieldType.clear();
3698 sContent.clear();
3699 bool bNewParagraph = false;
3700
3701 if (aType == chart2::DataPointCustomLabelFieldType_CELLRANGE &&
3702 rField->getDataLabelsRange())
3703 {
3704 if (rDLblsRange.getRange().isEmpty())
3705 rDLblsRange.setRange(rField->getCellRange());
3706
3707 if (!rDLblsRange.hasLabel(nLabelIndex))
3708 rDLblsRange.setLabel(nLabelIndex, rField->getString());
3709
3710 sContent = "[CELLRANGE]";
3711 }
3712 else
3713 {
3714 sContent = rField->getString();
3715 }
3716
3717 if (aType == chart2::DataPointCustomLabelFieldType_NEWLINE)
3718 bNewParagraph = true;
3719 else if (aType != chart2::DataPointCustomLabelFieldType_TEXT)
3720 sFieldType = getFieldTypeString(aType);
3721
3722 if (bNewParagraph)
3723 {
3724 pFS->endElement(FSNS(XML_a, XML_p));
3725 pFS->startElement(FSNS(XML_a, XML_p));
3726 continue;
3727 }
3728
3729 if (sFieldType.isEmpty())
3730 {
3731 // Normal text run
3732 pFS->startElement(FSNS(XML_a, XML_r));
3733 writeRunProperties(pChartExport, xPropertySet);
3734
3735 pFS->startElement(FSNS(XML_a, XML_t));
3736 pFS->writeEscaped(sContent);
3737 pFS->endElement(FSNS(XML_a, XML_t));
3738
3739 pFS->endElement(FSNS(XML_a, XML_r));
3740 }
3741 else
3742 {
3743 // Field
3744 pFS->startElement(FSNS(XML_a, XML_fld), XML_id, rField->getGuid(), XML_type,
3745 sFieldType);
3746 writeRunProperties(pChartExport, xPropertySet);
3747
3748 pFS->startElement(FSNS(XML_a, XML_t));
3749 pFS->writeEscaped(sContent);
3750 pFS->endElement(FSNS(XML_a, XML_t));
3751
3752 pFS->endElement(FSNS(XML_a, XML_fld));
3753 }
3754 }
3755
3756 pFS->endElement(FSNS(XML_a, XML_p));
3757 pFS->endElement(FSNS(XML_c, XML_rich));
3758 pFS->endElement(FSNS(XML_c, XML_tx));
3759}
3760
3761void writeLabelProperties( const FSHelperPtr& pFS, ChartExport* pChartExport,
3762 const uno::Reference<beans::XPropertySet>& xPropSet, const LabelPlacementParam& rLabelParam,
3763 sal_Int32 nLabelIndex, DataLabelsRange& rDLblsRange )
3764{
3765 if (!xPropSet.is())
3766 return;
3767
3768 chart2::DataPointLabel aLabel;
3769 Sequence<Reference<chart2::XDataPointCustomLabelField>> aCustomLabelFields;
3770 sal_Int32 nLabelBorderWidth = 0;
3771 sal_Int32 nLabelBorderColor = 0x00FFFFFF;
3772 sal_Int32 nLabelFillColor = -1;
3773
3774 xPropSet->getPropertyValue("Label") >>= aLabel;
3775 xPropSet->getPropertyValue("CustomLabelFields") >>= aCustomLabelFields;
3776 xPropSet->getPropertyValue("LabelBorderWidth") >>= nLabelBorderWidth;
3777 xPropSet->getPropertyValue("LabelBorderColor") >>= nLabelBorderColor;
3778 xPropSet->getPropertyValue("LabelFillColor") >>= nLabelFillColor;
3779
3780 if (nLabelBorderWidth > 0 || nLabelFillColor != -1)
3781 {
3782 pFS->startElement(FSNS(XML_c, XML_spPr));
3783
3784 if (nLabelFillColor != -1)
3785 {
3786 pFS->startElement(FSNS(XML_a, XML_solidFill));
3787
3788 OString aStr = OString::number(nLabelFillColor, 16).toAsciiUpperCase();
3789 pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr);
3790
3791 pFS->endElement(FSNS(XML_a, XML_solidFill));
3792 }
3793
3794 if (nLabelBorderWidth > 0)
3795 {
3796 pFS->startElement(FSNS(XML_a, XML_ln), XML_w,
3797 OString::number(convertHmmToEmu(nLabelBorderWidth)));
3798
3799 if (nLabelBorderColor != -1)
3800 {
3801 pFS->startElement(FSNS(XML_a, XML_solidFill));
3802
3803 OString aStr = OString::number(nLabelBorderColor, 16).toAsciiUpperCase();
3804 pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr);
3805
3806 pFS->endElement(FSNS(XML_a, XML_solidFill));
3807 }
3808
3809 pFS->endElement(FSNS(XML_a, XML_ln));
3810 }
3811
3812 pFS->endElement(FSNS(XML_c, XML_spPr));
3813 }
3814
3815 pChartExport->exportTextProps(xPropSet);
3816
3817 if (aCustomLabelFields.hasElements())
3818 writeCustomLabel(pFS, pChartExport, aCustomLabelFields, nLabelIndex, rDLblsRange);
3819
3820 if (rLabelParam.mbExport)
3821 {
3822 sal_Int32 nLabelPlacement = rLabelParam.meDefault;
3823 if (xPropSet->getPropertyValue("LabelPlacement") >>= nLabelPlacement)
3824 {
3825 if (!rLabelParam.maAllowedValues.count(nLabelPlacement))
3826 nLabelPlacement = rLabelParam.meDefault;
3827 pFS->singleElement(FSNS(XML_c, XML_dLblPos), XML_val, toOOXMLPlacement(nLabelPlacement));
3828 }
3829 }
3830
3831 pFS->singleElement(FSNS(XML_c, XML_showLegendKey), XML_val, ToPsz10(aLabel.ShowLegendSymbol));
3832 pFS->singleElement(FSNS(XML_c, XML_showVal), XML_val, ToPsz10(aLabel.ShowNumber));
3833 pFS->singleElement(FSNS(XML_c, XML_showCatName), XML_val, ToPsz10(aLabel.ShowCategoryName));
3834 pFS->singleElement(FSNS(XML_c, XML_showSerName), XML_val, ToPsz10(aLabel.ShowSeriesName));
3835 pFS->singleElement(FSNS(XML_c, XML_showPercent), XML_val, ToPsz10(aLabel.ShowNumberInPercent));
3836
3837 // Export the text "separator" if exists
3838 uno::Any aAny = xPropSet->getPropertyValue("LabelSeparator");
3839 if( aAny.hasValue() )
3840 {
3841 OUString nLabelSeparator;
3842 aAny >>= nLabelSeparator;
3843 pFS->startElement(FSNS(XML_c, XML_separator));
3844 pFS->writeEscaped( nLabelSeparator );
3845 pFS->endElement( FSNS( XML_c, XML_separator ) );
3846 }
3847
3848 if (rDLblsRange.hasLabel(nLabelIndex))
3849 {
3850 pFS->startElement(FSNS(XML_c, XML_extLst));
3851 pFS->startElement(FSNS(XML_c, XML_ext), XML_uri,
3852 "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}", FSNS(XML_xmlns, XML_c15),
3853 pChartExport->GetFB()->getNamespaceURL(OOX_NS(c15)));
3854
3855 pFS->singleElement(FSNS(XML_c15, XML_showDataLabelsRange), XML_val, "1");
3856
3857 pFS->endElement(FSNS(XML_c, XML_ext));
3858 pFS->endElement(FSNS(XML_c, XML_extLst));
3859 }
3860}
3861
3862}
3863
3865 const uno::Reference<chart2::XDataSeries> & xSeries, sal_Int32 nSeriesLength, sal_Int32 eChartType,
3866 DataLabelsRange& rDLblsRange)
3867{
3868 if (!xSeries.is() || nSeriesLength <= 0)
3869 return;
3870
3871 uno::Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
3872 if (!xPropSet.is())
3873 return;
3874
3875 FSHelperPtr pFS = GetFS();
3876 pFS->startElement(FSNS(XML_c, XML_dLbls));
3877
3878 bool bLinkedNumFmt = true;
3879 if (GetProperty(xPropSet, "LinkNumberFormatToSource"))
3880 mAny >>= bLinkedNumFmt;
3881
3882 chart2::DataPointLabel aLabel;
3883 bool bLabelIsNumberFormat = true;
3884 if( xPropSet->getPropertyValue("Label") >>= aLabel )
3885 bLabelIsNumberFormat = aLabel.ShowNumber;
3886
3887 if (GetProperty(xPropSet, bLabelIsNumberFormat ? OUString("NumberFormat") : OUString("PercentageNumberFormat")))
3888 {
3889 sal_Int32 nKey = 0;
3890 mAny >>= nKey;
3891
3892 OUString aNumberFormatString = getNumberFormatCode(nKey);
3893
3894 pFS->singleElement(FSNS(XML_c, XML_numFmt),
3895 XML_formatCode, aNumberFormatString,
3896 XML_sourceLinked, ToPsz10(bLinkedNumFmt));
3897 }
3898
3899 uno::Sequence<sal_Int32> aAttrLabelIndices;
3900 xPropSet->getPropertyValue("AttributedDataPoints") >>= aAttrLabelIndices;
3901
3902 // We must not export label placement property when the chart type doesn't
3903 // support this option in MS Office, else MS Office would think the file
3904 // is corrupt & refuse to open it.
3905
3906 const chart::TypeGroupInfo& rInfo = chart::GetTypeGroupInfo(static_cast<chart::TypeId>(eChartType));
3907 LabelPlacementParam aParam(!mbIs3DChart, rInfo.mnDefLabelPos);
3908 switch (eChartType) // diagram chart type
3909 {
3910 case chart::TYPEID_PIE:
3912 aParam.mbExport = false;
3913 else
3914 // All pie charts support label placement.
3915 aParam.mbExport = true;
3916 break;
3917 case chart::TYPEID_AREA:
3920 // These chart types don't support label placement.
3921 aParam.mbExport = false;
3922 break;
3923 case chart::TYPEID_BAR:
3924 if (mbStacked || mbPercent)
3925 {
3926 aParam.maAllowedValues.clear();
3927 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3928 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3929 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3930 aParam.meDefault = css::chart::DataLabelPlacement::CENTER;
3931 }
3932 else // Clustered bar chart
3933 {
3934 aParam.maAllowedValues.clear();
3935 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3936 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3937 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::OUTSIDE);
3938 aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3939 aParam.meDefault = css::chart::DataLabelPlacement::OUTSIDE;
3940 }
3941 break;
3942 default:
3943 ;
3944 }
3945
3946 for (const sal_Int32 nIdx : std::as_const(aAttrLabelIndices))
3947 {
3948 uno::Reference<beans::XPropertySet> xLabelPropSet = xSeries->getDataPointByIndex(nIdx);
3949
3950 if (!xLabelPropSet.is())
3951 continue;
3952
3953 pFS->startElement(FSNS(XML_c, XML_dLbl));
3954 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nIdx));
3955
3956 // export custom position of data label
3957 if( eChartType != chart::TYPEID_PIE )
3958 {
3959 chart2::RelativePosition aCustomLabelPosition;
3960 if( xLabelPropSet->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition )
3961 {
3962 pFS->startElement(FSNS(XML_c, XML_layout));
3963 pFS->startElement(FSNS(XML_c, XML_manualLayout));
3964
3965 pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(aCustomLabelPosition.Primary));
3966 pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(aCustomLabelPosition.Secondary));
3967
3968 SAL_WARN_IF(aCustomLabelPosition.Anchor != css::drawing::Alignment_TOP_LEFT, "oox", "unsupported anchor position");
3969
3970 pFS->endElement(FSNS(XML_c, XML_manualLayout));
3971 pFS->endElement(FSNS(XML_c, XML_layout));
3972 }
3973 }
3974
3975 if( GetProperty(xLabelPropSet, "LinkNumberFormatToSource") )
3976 mAny >>= bLinkedNumFmt;
3977
3978 if( xLabelPropSet->getPropertyValue("Label") >>= aLabel )
3979 bLabelIsNumberFormat = aLabel.ShowNumber;
3980 else
3981 bLabelIsNumberFormat = true;
3982
3983 if (GetProperty(xLabelPropSet, bLabelIsNumberFormat ? OUString("NumberFormat") : OUString("PercentageNumberFormat")))
3984 {
3985 sal_Int32 nKey = 0;
3986 mAny >>= nKey;
3987
3988 OUString aNumberFormatString = getNumberFormatCode(nKey);
3989
3990 pFS->singleElement(FSNS(XML_c, XML_numFmt), XML_formatCode, aNumberFormatString,
3991 XML_sourceLinked, ToPsz10(bLinkedNumFmt));
3992 }
3993
3994 // Individual label property that overwrites the baseline.
3995 writeLabelProperties(pFS, this, xLabelPropSet, aParam, nIdx, rDLblsRange);
3996 pFS->endElement(FSNS(XML_c, XML_dLbl));
3997 }
3998
3999 // Baseline label properties for all labels.
4000 writeLabelProperties(pFS, this, xPropSet, aParam, -1, rDLblsRange);
4001
4002 bool bShowLeaderLines = false;
4003 xPropSet->getPropertyValue("ShowCustomLeaderLines") >>= bShowLeaderLines;
4004 pFS->singleElement(FSNS(XML_c, XML_showLeaderLines), XML_val, ToPsz10(bShowLeaderLines));
4005
4006 // Export leader line
4007 if( eChartType != chart::TYPEID_PIE )
4008 {
4009 pFS->startElement(FSNS(XML_c, XML_extLst));
4010 pFS->startElement(FSNS(XML_c, XML_ext), XML_uri, "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}", FSNS(XML_xmlns, XML_c15), GetFB()->getNamespaceURL(OOX_NS(c15)));
4011 pFS->singleElement(FSNS(XML_c15, XML_showLeaderLines), XML_val, ToPsz10(bShowLeaderLines));
4012 pFS->endElement(FSNS(XML_c, XML_ext));
4013 pFS->endElement(FSNS(XML_c, XML_extLst));
4014 }
4015 pFS->endElement(FSNS(XML_c, XML_dLbls));
4016}
4017
4019 const uno::Reference< beans::XPropertySet > & xSeriesProperties,
4020 sal_Int32 nSeriesLength, sal_Int32 eChartType )
4021{
4022 uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
4023 bool bVaryColorsByPoint = false;
4024 Sequence< sal_Int32 > aDataPointSeq;
4025 if( xSeriesProperties.is())
4026 {
4027 Any aAny = xSeriesProperties->getPropertyValue( "AttributedDataPoints" );
4028 aAny >>= aDataPointSeq;
4029 xSeriesProperties->getPropertyValue( "VaryColorsByPoint" ) >>= bVaryColorsByPoint;
4030 }
4031
4032 const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
4033 sal_Int32 nElement;
4035 if( mxNewDiagram.is())
4036 xColorScheme.set( mxNewDiagram->getDefaultColorScheme());
4037
4038 if( bVaryColorsByPoint && xColorScheme.is() )
4039 {
4041 aAttrPointSet.reserve(aDataPointSeq.getLength());
4042 for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
4043 aAttrPointSet.insert(*p);
4044 const auto aEndIt = aAttrPointSet.end();
4045 for( nElement = 0; nElement < nSeriesLength; ++nElement )
4046 {
4047 uno::Reference< beans::XPropertySet > xPropSet;
4048 if( aAttrPointSet.find( nElement ) != aEndIt )
4049 {
4050 try
4051 {
4053 xSeries, nElement, getModel() );
4054 }
4055 catch( const uno::Exception & )
4056 {
4057 DBG_UNHANDLED_EXCEPTION( "oox", "Exception caught during Export of data point" );
4058 }
4059 }
4060 else
4061 {
4062 // property set only containing the color
4063 xPropSet.set( new ColorPropertySet( ColorTransparency, xColorScheme->getColorByIndex( nElement )));
4064 }
4065
4066 if( xPropSet.is() )
4067 {
4068 FSHelperPtr pFS = GetFS();
4069 pFS->startElement(FSNS(XML_c, XML_dPt));
4070 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nElement));
4071
4072 switch (eChartType)
4073 {
4074 case chart::TYPEID_PIE:
4076 {
4077 if( xPropSet.is() && GetProperty( xPropSet, "SegmentOffset") )
4078 {
4079 sal_Int32 nOffset = 0;
4080 mAny >>= nOffset;
4081 if (nOffset)
4082 pFS->singleElement( FSNS( XML_c, XML_explosion ),
4083 XML_val, OString::number( nOffset ) );
4084 }
4085 break;
4086 }
4087 default:
4088 break;
4089 }
4090 exportShapeProps( xPropSet );
4091
4092 pFS->endElement( FSNS( XML_c, XML_dPt ) );
4093 }
4094 }
4095 }
4096
4097 // Export Data Point Property in Charts even if the VaryColors is false
4098 if( bVaryColorsByPoint )
4099 return;
4100
4102 aAttrPointSet.reserve(aDataPointSeq.getLength());
4103 for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
4104 aAttrPointSet.insert(*p);
4105 const auto aEndIt = aAttrPointSet.end();
4106 for( nElement = 0; nElement < nSeriesLength; ++nElement )
4107 {
4108 uno::Reference< beans::XPropertySet > xPropSet;
4109 if( aAttrPointSet.find( nElement ) != aEndIt )
4110 {
4111 try
4112 {
4114 xSeries, nElement, getModel() );
4115 }
4116 catch( const uno::Exception & )
4117 {
4118 DBG_UNHANDLED_EXCEPTION( "oox", "Exception caught during Export of data point" );
4119 }
4120 }
4121
4122 if( xPropSet.is() )
4123 {
4124 FSHelperPtr pFS = GetFS();
4125 pFS->startElement(FSNS(XML_c, XML_dPt));
4126 pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nElement));
4127
4128 switch( eChartType )
4129 {
4132 case chart::TYPEID_BAR:
4133 pFS->singleElement(FSNS(XML_c, XML_invertIfNegative), XML_val, "0");
4134 exportShapeProps(xPropSet);
4135 break;
4136
4137 case chart::TYPEID_LINE:
4140 exportMarker(xPropSet);
4141 break;
4142
4143 default:
4144 exportShapeProps(xPropSet);
4145 break;
4146 }
4147
4148 pFS->endElement( FSNS( XML_c, XML_dPt ) );
4149 }
4150 }
4151}
4152
4153void ChartExport::exportAxesId(bool bPrimaryAxes, bool bCheckCombinedAxes)
4154{
4155 sal_Int32 nAxisIdx, nAxisIdy;
4156 bool bPrimaryAxisExists = false;
4157 bool bSecondaryAxisExists = false;
4158 // let's check which axis already exists and which axis is attached to the actual dataseries
4159 if (maAxes.size() >= 2)
4160 {
4161 bPrimaryAxisExists = bPrimaryAxes && maAxes[1].nAxisType == AXIS_PRIMARY_Y;
4162 bSecondaryAxisExists = !bPrimaryAxes && maAxes[1].nAxisType == AXIS_SECONDARY_Y;
4163 }
4164 // tdf#114181 keep axes of combined charts
4165 if ( bCheckCombinedAxes && ( bPrimaryAxisExists || bSecondaryAxisExists ) )
4166 {
4167 nAxisIdx = maAxes[0].nAxisId;
4168 nAxisIdy = maAxes[1].nAxisId;
4169 }
4170 else
4171 {
4172 nAxisIdx = lcl_generateRandomValue();
4173 nAxisIdy = lcl_generateRandomValue();
4174 AxesType eXAxis = bPrimaryAxes ? AXIS_PRIMARY_X : AXIS_SECONDARY_X;
4175 AxesType eYAxis = bPrimaryAxes ? AXIS_PRIMARY_Y : AXIS_SECONDARY_Y;
4176 maAxes.emplace_back( eXAxis, nAxisIdx, nAxisIdy );
4177 maAxes.emplace_back( eYAxis, nAxisIdy, nAxisIdx );
4178 }
4179 FSHelperPtr pFS = GetFS();
4180 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdx));
4181 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdy));
4182 if (mbHasZAxis)
4183 {
4184 sal_Int32 nAxisIdz = 0;
4185 if( isDeep3dChart() )
4186 {
4187 nAxisIdz = lcl_generateRandomValue();
4188 maAxes.emplace_back( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy );
4189 }
4190 pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdz));
4191 }
4192}
4193
4195{
4196 FSHelperPtr pFS = GetFS();
4197 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4198 // grouping
4199 if( GetProperty( xPropSet, "Stacked" ) )
4200 mAny >>= mbStacked;
4201 if( GetProperty( xPropSet, "Percent" ) )
4202 mAny >>= mbPercent;
4203
4204 const char* grouping = nullptr;
4205 if (mbStacked)
4206 grouping = "stacked";
4207 else if (mbPercent)
4208 grouping = "percentStacked";
4209 else
4210 {
4211 if( isBar && !isDeep3dChart() )
4212 {
4213 grouping = "clustered";
4214 }
4215 else
4216 grouping = "standard";
4217 }
4218 pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, grouping);
4219}
4220
4222{
4223 FSHelperPtr pFS = GetFS();
4224 Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, UNO_QUERY );
4225 if( !xRegressionCurveContainer.is() )
4226 return;
4227
4228 const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
4229 for( const Reference< chart2::XRegressionCurve >& xRegCurve : aRegCurveSeq )
4230 {
4231 if (!xRegCurve.is())
4232 continue;
4233
4234 Reference< XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
4235
4236 OUString aService;
4237 Reference< lang::XServiceName > xServiceName( xProperties, UNO_QUERY );
4238 if( !xServiceName.is() )
4239 continue;
4240
4241 aService = xServiceName->getServiceName();
4242
4243 if(aService != "com.sun.star.chart2.LinearRegressionCurve" &&
4244 aService != "com.sun.star.chart2.ExponentialRegressionCurve" &&
4245 aService != "com.sun.star.chart2.LogarithmicRegressionCurve" &&
4246 aService != "com.sun.star.chart2.PotentialRegressionCurve" &&
4247 aService != "com.sun.star.chart2.PolynomialRegressionCurve" &&
4248 aService != "com.sun.star.chart2.MovingAverageRegressionCurve")
4249 continue;
4250
4251 pFS->startElement(FSNS(XML_c, XML_trendline));
4252
4253 OUString aName;
4254 xProperties->getPropertyValue("CurveName") >>= aName;
4255 if(!aName.isEmpty())
4256 {
4257 pFS->startElement(FSNS(XML_c, XML_name));
4258 pFS->writeEscaped(aName);
4259 pFS->endElement( FSNS( XML_c, XML_name) );
4260 }
4261
4262 exportShapeProps( xProperties );
4263
4264 if( aService == "com.sun.star.chart2.LinearRegressionCurve" )
4265 {
4266 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "linear");
4267 }
4268 else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
4269 {
4270 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "exp");
4271 }
4272 else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
4273 {
4274 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "log");
4275 }
4276 else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
4277 {
4278 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "power");
4279 }
4280 else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
4281 {
4282 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "poly");
4283
4284 sal_Int32 aDegree = 2;
4285 xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
4286 pFS->singleElement(FSNS(XML_c, XML_order), XML_val, OString::number(aDegree));
4287 }
4288 else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
4289 {
4290 pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "movingAvg");
4291
4292 sal_Int32 aPeriod = 2;
4293 xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
4294
4295 pFS->singleElement(FSNS(XML_c, XML_period), XML_val, OString::number(aPeriod));
4296 }
4297 else
4298 {
4299 // should never happen
4300 // This would produce invalid OOXML files so we check earlier for the type
4301 assert(false);
4302 }
4303
4304 double fExtrapolateForward = 0.0;
4305 double fExtrapolateBackward = 0.0;
4306
4307 xProperties->getPropertyValue("ExtrapolateForward") >>= fExtrapolateForward;
4308 xProperties->getPropertyValue("ExtrapolateBackward") >>= fExtrapolateBackward;
4309
4310 pFS->singleElement( FSNS( XML_c, XML_forward ),
4311 XML_val, OString::number(fExtrapolateForward) );
4312
4313 pFS->singleElement( FSNS( XML_c, XML_backward ),
4314 XML_val, OString::number(fExtrapolateBackward) );
4315
4316 bool bForceIntercept = false;
4317 xProperties->getPropertyValue("ForceIntercept") >>= bForceIntercept;
4318
4319 if (bForceIntercept)
4320 {
4321 double fInterceptValue = 0.0;
4322 xProperties->getPropertyValue("InterceptValue") >>= fInterceptValue;
4323
4324 pFS->singleElement( FSNS( XML_c, XML_intercept ),
4325 XML_val, OString::number(fInterceptValue) );
4326 }
4327
4328 // Equation properties
4329 Reference< XPropertySet > xEquationProperties( xRegCurve->getEquationProperties() );
4330
4331 // Show Equation
4332 bool bShowEquation = false;
4333 xEquationProperties->getPropertyValue("ShowEquation") >>= bShowEquation;
4334
4335 // Show R^2
4336 bool bShowCorrelationCoefficient = false;
4337 xEquationProperties->getPropertyValue("ShowCorrelationCoefficient") >>= bShowCorrelationCoefficient;
4338
4339 pFS->singleElement( FSNS( XML_c, XML_dispRSqr ),
4340 XML_val, ToPsz10(bShowCorrelationCoefficient) );
4341
4342 pFS->singleElement(FSNS(XML_c, XML_dispEq), XML_val, ToPsz10(bShowEquation));
4343
4344 pFS->endElement( FSNS( XML_c, XML_trendline ) );
4345 }
4346}
4347
4349{
4350 chart2::Symbol aSymbol;
4351 if( GetProperty( xPropSet, "Symbol" ) )
4352 mAny >>= aSymbol;
4353
4354 if(aSymbol.Style != chart2::SymbolStyle_STANDARD && aSymbol.Style != chart2::SymbolStyle_NONE)
4355 return;
4356
4357 FSHelperPtr pFS = GetFS();
4358 pFS->startElement(FSNS(XML_c, XML_marker));
4359
4360 sal_Int32 nSymbol = aSymbol.StandardSymbol;
4361 // TODO: more properties support for marker
4362 const char* pSymbolType; // no initialization here, to let compiler warn if we have a code path
4363 // where it stays uninitialized
4364 switch( nSymbol )
4365 {
4366 case 0:
4367 pSymbolType = "square";
4368 break;
4369 case 1:
4370 pSymbolType = "diamond";
4371 break;
4372 case 2:
4373 case 3:
4374 case 4:
4375 case 5:
4376 pSymbolType = "triangle";
4377 break;
4378 case 8:
4379 pSymbolType = "circle";
4380 break;
4381 case 9:
4382 pSymbolType = "star";
4383 break;
4384 case 10:
4385 pSymbolType = "x"; // in MS office 2010 built in symbol marker 'X' is represented as 'x'
4386 break;
4387 case 11:
4388 pSymbolType = "plus";
4389 break;
4390 case 13:
4391 pSymbolType = "dash";
4392 break;
4393 default:
4394 pSymbolType = "square";
4395 break;
4396 }
4397
4398 bool bSkipFormatting = false;
4399 if (aSymbol.Style == chart2::SymbolStyle_NONE)
4400 {
4401 bSkipFormatting = true;
4402 pSymbolType = "none";
4403 }
4404
4405 pFS->singleElement(FSNS(XML_c, XML_symbol), XML_val, pSymbolType);
4406
4407 if (!bSkipFormatting)
4408 {
4409 awt::Size aSymbolSize = aSymbol.Size;
4410 sal_Int32 nSize = std::max( aSymbolSize.Width, aSymbolSize.Height );
4411
4412 nSize = nSize/250.0*7.0 + 1; // just guessed based on some test cases,
4413 //the value is always 1 less than the actual value.
4414 nSize = std::clamp( int(nSize), 2, 72 );
4415 pFS->singleElement(FSNS(XML_c, XML_size), XML_val, OString::number(nSize));
4416
4417 pFS->startElement(FSNS(XML_c, XML_spPr));
4418
4419 util::Color aColor = aSymbol.FillColor;
4420 if (GetProperty(xPropSet, "Color"))
4421 mAny >>= aColor;
4422
4423 if (aColor == -1)
4424 {
4425 pFS->singleElement(FSNS(XML_a, XML_noFill));
4426 }
4427 else
4429
4430 pFS->endElement( FSNS( XML_c, XML_spPr ) );
4431 }
4432
4433 pFS->endElement( FSNS( XML_c, XML_marker ) );
4434}
4435
4437{
4438 FSHelperPtr pFS = GetFS();
4439 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY );
4440 sal_Int32 nSplineType = 0;
4441 if( GetProperty( xPropSet, "SplineType" ) )
4442 mAny >>= nSplineType;
4443 const char* pVal = nSplineType != 0 ? "1" : "0";
4444 pFS->singleElement(FSNS(XML_c, XML_smooth), XML_val, pVal);
4445}
4446
4448{
4449 FSHelperPtr pFS = GetFS();
4450 sal_Int32 nStartingAngle = 0;
4451 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4452 if( GetProperty( xPropSet, "StartingAngle" ) )
4453 mAny >>= nStartingAngle;
4454
4455 // convert to ooxml angle
4456 nStartingAngle = (450 - nStartingAngle ) % 360;
4457 pFS->singleElement(FSNS(XML_c, XML_firstSliceAng), XML_val, OString::number(nStartingAngle));
4458}
4459
4460namespace {
4461
4462const char* getErrorBarStyle(sal_Int32 nErrorBarStyle)
4463{
4464 switch(nErrorBarStyle)
4465 {
4466 case cssc::ErrorBarStyle::NONE:
4467 return nullptr;
4468 case cssc::ErrorBarStyle::VARIANCE:
4469 break;
4470 case cssc::ErrorBarStyle::STANDARD_DEVIATION:
4471 return "stdDev";
4472 case cssc::ErrorBarStyle::ABSOLUTE:
4473 return "fixedVal";
4474 case cssc::ErrorBarStyle::RELATIVE:
4475 return "percentage";
4476 case cssc::ErrorBarStyle::ERROR_MARGIN:
4477 break;
4478 case cssc::ErrorBarStyle::STANDARD_ERROR:
4479 return "stdErr";
4480 case cssc::ErrorBarStyle::FROM_DATA:
4481 return "cust";
4482 default:
4483 assert(false && "can't happen");
4484 }
4485 return nullptr;
4486}
4487
4488Reference< chart2::data::XDataSequence> getLabeledSequence(
4489 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences,
4490 bool bPositive )
4491{
4492 OUString aDirection;
4493 if(bPositive)
4494 aDirection = "positive";
4495 else
4496 aDirection = "negative";
4497
4498 for( const auto& rSequence : aSequences )
4499 {
4500 if( rSequence.is())
4501 {
4502 uno::Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues());
4503 uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
4504 OUString aRole;
4505 if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) &&
4506 aRole.match( "error-bars" ) && aRole.indexOf(aDirection) >= 0 )
4507 {
4508 return xSequence;
4509 }
4510 }
4511 }
4512
4513 return Reference< chart2::data::XDataSequence > ();
4514}
4515
4516}
4517
4518void ChartExport::exportErrorBar(const Reference< XPropertySet>& xErrorBarProps, bool bYError)
4519{
4520 sal_Int32 nErrorBarStyle = cssc::ErrorBarStyle::NONE;
4521 xErrorBarProps->getPropertyValue("ErrorBarStyle") >>= nErrorBarStyle;
4522 const char* pErrorBarStyle = getErrorBarStyle(nErrorBarStyle);
4523 if(!pErrorBarStyle)
4524 return;
4525
4526 FSHelperPtr pFS = GetFS();
4527 pFS->startElement(FSNS(XML_c, XML_errBars));
4528 pFS->singleElement(FSNS(XML_c, XML_errDir), XML_val, bYError ? "y" : "x");
4529 bool bPositive = false, bNegative = false;
4530 xErrorBarProps->getPropertyValue("ShowPositiveError") >>= bPositive;
4531 xErrorBarProps->getPropertyValue("ShowNegativeError") >>= bNegative;
4532 const char* pErrBarType;
4533 if(bPositive && bNegative)
4534 pErrBarType = "both";
4535 else if(bPositive)
4536 pErrBarType = "plus";
4537 else if(bNegative)
4538 pErrBarType = "minus";
4539 else
4540 {
4541 // what the hell should we do now?
4542 // at least this makes the file valid
4543 pErrBarType = "both";
4544 }
4545 pFS->singleElement(FSNS(XML_c, XML_errBarType), XML_val, pErrBarType);
4546 pFS->singleElement(FSNS(XML_c, XML_errValType), XML_val, pErrorBarStyle);
4547 pFS->singleElement(FSNS(XML_c, XML_noEndCap), XML_val, "0");
4548 if(nErrorBarStyle == cssc::ErrorBarStyle::FROM_DATA)
4549 {
4550 uno::Reference< chart2::data::XDataSource > xDataSource(xErrorBarProps, uno::UNO_QUERY);
4552 xDataSource->getDataSequences();
4553
4554 if(bPositive)
4555 {
4556 exportSeriesValues(getLabeledSequence(aSequences, true), XML_plus);
4557 }
4558
4559 if(bNegative)
4560 {
4561 exportSeriesValues(getLabeledSequence(aSequences, false), XML_minus);
4562 }
4563 }
4564 else
4565 {
4566 double nVal = 0.0;
4567 if(nErrorBarStyle == cssc::ErrorBarStyle::STANDARD_DEVIATION)
4568 {
4569 xErrorBarProps->getPropertyValue("Weight") >>= nVal;
4570 }
4571 else
4572 {
4573 if(bPositive)
4574 xErrorBarProps->getPropertyValue("PositiveError") >>= nVal;
4575 else
4576 xErrorBarProps->getPropertyValue("NegativeError") >>= nVal;
4577 }
4578
4579 pFS->singleElement(FSNS(XML_c, XML_val), XML_val, OString::number(nVal));
4580 }
4581
4582 exportShapeProps( xErrorBarProps );
4583
4584 pFS->endElement( FSNS( XML_c, XML_errBars) );
4585}
4586
4588{
4589 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4590 if( !xPropSet.is() )
4591 return;
4592 FSHelperPtr pFS = GetFS();
4593 pFS->startElement(FSNS(XML_c, XML_view3D));
4594 sal_Int32 eChartType = getChartType( );
4595 // rotX
4596 if( GetProperty( xPropSet, "RotationHorizontal" ) )
4597 {
4598 sal_Int32 nRotationX = 0;
4599 mAny >>= nRotationX;
4600 if( nRotationX < 0 )
4601 {
4602 if(eChartType == chart::TYPEID_PIE)
4603 {
4604 /* In OOXML we get value in 0..90 range for pie chart X rotation , whereas we expect it to be in -90..90 range,
4605 so we convert that during import. It is modified in View3DConverter::convertFromModel()
4606 here we convert it back to 0..90 as we received in import */
4607 nRotationX += 90; // X rotation (map Chart2 [-179,180] to OOXML [0..90])
4608 }
4609 else
4610 nRotationX += 360; // X rotation (map Chart2 [-179,180] to OOXML [-90..90])
4611 }
4612 pFS->singleElement(FSNS(XML_c, XML_rotX), XML_val, OString::number(nRotationX));
4613 }
4614 // rotY
4615 if( GetProperty( xPropSet, "RotationVertical" ) )
4616 {
4617 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
4618 if( eChartType == chart::TYPEID_PIE && GetProperty( xPropSet, "StartingAngle" ) )
4619 {
4620 // Y rotation used as 'first pie slice angle' in 3D pie charts
4621 sal_Int32 nStartingAngle=0;
4622 mAny >>= nStartingAngle;
4623 // convert to ooxml angle
4624 nStartingAngle = (450 - nStartingAngle ) % 360;
4625 pFS->singleElement(FSNS(XML_c, XML_rotY), XML_val, OString::number(nStartingAngle));
4626 }
4627 else
4628 {
4629 sal_Int32 nRotationY = 0;
4630 mAny >>= nRotationY;
4631 // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
4632 if( nRotationY < 0 )
4633 nRotationY += 360;
4634 pFS->singleElement(FSNS(XML_c, XML_rotY), XML_val, OString::number(nRotationY));
4635 }
4636 }
4637 // rAngAx
4638 if( GetProperty( xPropSet, "RightAngledAxes" ) )
4639 {
4640 bool bRightAngled = false;
4641 mAny >>= bRightAngled;
4642 const char* sRightAngled = bRightAngled ? "1":"0";
4643 pFS->singleElement(FSNS(XML_c, XML_rAngAx), XML_val, sRightAngled);
4644 }
4645 // perspective
4646 if( GetProperty( xPropSet, "Perspective" ) )
4647 {
4648 sal_Int32 nPerspective = 0;
4649 mAny >>= nPerspective;
4650 // map Chart2 [0,100] to OOXML [0..200]
4651 nPerspective *= 2;
4652 pFS->singleElement(FSNS(XML_c, XML_perspective), XML_val, OString::number(nPerspective));
4653 }
4654 pFS->endElement( FSNS( XML_c, XML_view3D ) );
4655}
4656
4658{
4659 bool isDeep = false;
4660 if( mbIs3DChart )
4661 {
4662 Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4663 if( GetProperty( xPropSet, "Deep" ) )
4664 mAny >>= isDeep;
4665 }
4666 return isDeep;
4667}
4668
4669OUString ChartExport::getNumberFormatCode(sal_Int32 nKey) const
4670{
4671 /* XXX if this was called more than one or two times per export the two
4672 * SvNumberFormatter instances and NfKeywordTable should be member
4673 * variables and initialized only once. */
4674
4675 OUString aCode("General"); // init with fallback
4676 uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(mxChartModel, uno::UNO_QUERY_THROW);
4677 SvNumberFormatsSupplierObj* pSupplierObj = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xNumberFormatsSupplier);
4678 if (!pSupplierObj)
4679 return aCode;
4680
4681 SvNumberFormatter* pNumberFormatter = pSupplierObj->GetNumberFormatter();
4682 if (!pNumberFormatter)
4683 return aCode;
4684
4686 NfKeywordTable aKeywords;
4687 aTempFormatter.FillKeywordTableForExcel( aKeywords);
4688 aCode = pNumberFormatter->GetFormatStringForExcel( nKey, aKeywords, aTempFormatter);
4689
4690 return aCode;
4691}
4692
4693}// oox
4694
4695/* 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:354
::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:6033
::sax_fastparser::FSHelperPtr mpFS
Definition: drawingml.hxx:161
bool GetProperty(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &aName)
Definition: drawingml.cxx:291
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:1893
void WriteSolidFill(::Color nColor, sal_Int32 nAlpha=MAX_PERCENT)
Definition: drawingml.cxx:477
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:4879
void WriteOutline(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, css::uno::Reference< css::frame::XModel > const &xModel=nullptr)
Definition: drawingml.cxx:934
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:1668
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:2019
ShapeExport & WriteShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Write the DrawingML for a particular shape.
Definition: shapes.cxx:1984
ColorTransparency
#define TOOLS_WARN_EXCEPTION(area, stream)
#define TOOLS_INFO_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
OString sName
Definition: drawingml.cxx:4066
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