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