Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/chart/SchXMLExport.cxx
Line
Count
Source
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 <memory>
21
#include <sal/config.h>
22
#include <sal/log.hxx>
23
24
#include <sax/tools/converter.hxx>
25
26
#include <utility>
27
#include <xmloff/xmlprmap.hxx>
28
29
#include <SchXMLExport.hxx>
30
#include <XMLChartPropertySetMapper.hxx>
31
#include "ColorPropertySet.hxx"
32
#include "SchXMLTools.hxx"
33
#include "SchXMLEnumConverter.hxx"
34
35
#include <comphelper/processfactory.hxx>
36
#include <tools/globname.hxx>
37
#include <comphelper/classids.hxx>
38
#include <comphelper/errcode.hxx>
39
#include <comphelper/sequence.hxx>
40
41
#include <xmloff/maptype.hxx>
42
#include <xmloff/namespacemap.hxx>
43
#include <xmloff/xmlnamespace.hxx>
44
#include <xmloff/xmltoken.hxx>
45
#include <xmloff/families.hxx>
46
#include <xmloff/xmlaustp.hxx>
47
#include <xmloff/xmluconv.hxx>
48
#include <xmloff/SchXMLSeriesHelper.hxx>
49
#include <rtl/math.hxx>
50
#include <o3tl/sorted_vector.hxx>
51
#include <o3tl/string_view.hxx>
52
53
#include <limits>
54
#include <vector>
55
#include <algorithm>
56
#include <queue>
57
#include <iterator>
58
#include <numeric>
59
60
#include <com/sun/star/lang/XServiceInfo.hpp>
61
#include <com/sun/star/lang/XServiceName.hpp>
62
#include <com/sun/star/beans/XPropertySet.hpp>
63
#include <com/sun/star/uno/XComponentContext.hpp>
64
#include <com/sun/star/util/XRefreshable.hpp>
65
66
#include <com/sun/star/chart/XAxis.hpp>
67
#include <com/sun/star/chart/XAxisSupplier.hpp>
68
#include <com/sun/star/chart/XChartDocument.hpp>
69
#include <com/sun/star/chart/ChartLegendExpansion.hpp>
70
#include <com/sun/star/chart/ChartDataRowSource.hpp>
71
#include <com/sun/star/chart/ChartAxisAssign.hpp>
72
#include <com/sun/star/chart/ErrorBarStyle.hpp>
73
#include <com/sun/star/chart/DataLabelPlacement.hpp>
74
#include <com/sun/star/chart/TimeIncrement.hpp>
75
#include <com/sun/star/chart/TimeInterval.hpp>
76
#include <com/sun/star/chart/TimeUnit.hpp>
77
#include <com/sun/star/chart/X3DDisplay.hpp>
78
#include <com/sun/star/chart/XStatisticDisplay.hpp>
79
#include <com/sun/star/chart/XDiagramPositioning.hpp>
80
81
#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
82
#include <com/sun/star/chart2/AxisType.hpp>
83
#include <com/sun/star/chart2/XChartDocument.hpp>
84
#include <com/sun/star/chart2/XDiagram.hpp>
85
#include <com/sun/star/chart2/RelativePosition.hpp>
86
#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
87
#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
88
#include <com/sun/star/chart2/XChartTypeContainer.hpp>
89
#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
90
#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
91
#include <com/sun/star/chart2/data/XDataSource.hpp>
92
#include <com/sun/star/chart2/data/XDataSink.hpp>
93
#include <com/sun/star/chart2/data/XDataProvider.hpp>
94
#include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
95
#include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
96
#include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
97
#include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
98
99
#include <com/sun/star/util/MeasureUnit.hpp>
100
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
101
#include <com/sun/star/drawing/XShapes.hpp>
102
#include <com/sun/star/embed/Aspects.hpp>
103
#include <com/sun/star/embed/XVisualObject.hpp>
104
#include <com/sun/star/container/XChild.hpp>
105
106
#include <chart2/AbstractPivotTableDataProvider.hxx>
107
#include <comphelper/diagnose_ex.hxx>
108
#include "MultiPropertySetHandler.hxx"
109
#include "PropertyMap.hxx"
110
111
using namespace com::sun::star;
112
using namespace ::xmloff::token;
113
114
using ::com::sun::star::uno::Sequence;
115
using ::com::sun::star::uno::Reference;
116
using ::com::sun::star::uno::Any;
117
using ::std::vector;
118
119
namespace
120
{
121
    /**
122
     * Used to store a data point custom-label's fields and also the helper members that
123
     * indicates whether this label's contents are sourced from a cell[range] and
124
     * the address of the cell[range] with guid of the CELLRANGE field.
125
     */
126
    struct CustomLabelData
127
    {
128
        CustomLabelData():
129
0
            mbDataLabelsRange( false )
130
0
        {
131
0
        }
132
133
        /// Label fields.
134
        Sequence<Reference<chart2::XDataPointCustomLabelField>> maFields;
135
        /// Are label's contents sourced from a cell[range] ?
136
        bool mbDataLabelsRange;
137
        /// cell[range] from which label's contents are sourced.
138
        OUString maRange;
139
        /// GUID of the CELLRANGE field.
140
        OUString maGuid;
141
    };
142
143
    struct SchXMLDataPointStruct
144
    {
145
        OUString   maStyleName;
146
        sal_Int32  mnRepeat;
147
        chart2::RelativePosition mCustomLabelPos; // loext:custom-label-pos-x and -y
148
149
        // There is no internal equivalent for <chart:data-label>. It will be generated on the fly
150
        // on export. All about data label is hold in the data point.
151
        CustomLabelData   mCustomLabel; // <text:p> child element in <chart:data-label>
152
        OUString msDataLabelStyleName; // chart:style-name attribute in <chart:data-label>
153
154
0
        SchXMLDataPointStruct() : mnRepeat( 1 ) {}
155
    };
156
}
157
158
159
class SchXMLExportHelper_Impl
160
{
161
public:
162
    // first: data sequence for label, second: data sequence for values.
163
    typedef ::std::pair< css::uno::Reference< css::chart2::data::XDataSequence >,
164
            css::uno::Reference< css::chart2::data::XDataSequence > > tLabelValuesDataPair;
165
    typedef ::std::vector< tLabelValuesDataPair > tDataSequenceCont;
166
167
public:
168
    SchXMLExportHelper_Impl( SvXMLExport& rExport,
169
                        SvXMLAutoStylePoolP& rASPool );
170
171
    SchXMLExportHelper_Impl(const SchXMLExportHelper_Impl&) = delete;
172
    SchXMLExportHelper_Impl& operator=(const SchXMLExportHelper_Impl&) = delete;
173
174
    // auto-styles
175
    /// parse chart and collect all auto-styles used in current pool
176
    void collectAutoStyles( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc );
177
178
    /// write the styles collected into the current pool as <style:style> elements
179
    void exportAutoStyles();
180
181
    /** export the <chart:chart> element corresponding to rChartDoc
182
        if bIncludeTable is true, the chart data is exported as <table:table>
183
        element (inside the chart element).
184
185
        Otherwise the external references stored in the chart document are used
186
        for writing the corresponding attributes at series
187
188
        All attributes contained in xAttrList are written at the chart element,
189
        which is the outer element of a chart. So these attributes can easily
190
        be parsed again by the container
191
     */
192
    void exportChart( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc,
193
                      bool bIncludeTable );
194
195
    const rtl::Reference<XMLPropertySetMapper>& GetPropertySetMapper() const;
196
197
    void SetChartRangeAddress( const OUString& rAddress )
198
0
        { msChartAddress = rAddress; }
199
200
    void InitRangeSegmentationProperties(
201
        const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc );
202
203
    static css::awt::Size getPageSize(
204
        const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc );
205
206
    /** first parseDocument: collect autostyles and store names in this queue
207
        second parseDocument: export content and use names from this queue
208
     */
209
    ::std::queue< OUString > maAutoStyleNameQueue;
210
    void CollectAutoStyle(
211
        std::vector< XMLPropertyState >&& aStates );
212
    void CollectAutoTextStyle(
213
        const css::uno::Reference< css::beans::XPropertySet >& xTitlePropSet );
214
    void AddAutoStyleAttribute(
215
        const std::vector< XMLPropertyState >& aStates );
216
217
    /// if bExportContent is false the auto-styles are collected
218
    void parseDocument( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc,
219
                        bool bExportContent,
220
                        bool bIncludeTable = false );
221
    void exportTable();
222
    void exportPlotArea(
223
        const css::uno::Reference< css::chart::XDiagram >& xDiagram,
224
        const css::uno::Reference< css::chart2::XDiagram >& xNewDiagram,
225
        const css::awt::Size & rPageSize,
226
        bool bExportContent,
227
        bool bIncludeTable );
228
    void exportCoordinateRegion( const css::uno::Reference< css::chart::XDiagram >& xDiagram );
229
    void exportAxes( const css::uno::Reference< css::chart::XDiagram > & xDiagram,
230
                                    const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram,
231
                                    bool bExportContent );
232
    void exportAxis( enum XMLTokenEnum eDimension, enum XMLTokenEnum eAxisName,
233
                    const Reference< beans::XPropertySet >& rAxisProps, const Reference< chart2::XAxis >& rChart2Axis,
234
                    const OUString& rCategoriesRanges,
235
                    bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, bool bExportContent, std::u16string_view sChartType );
236
    void exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent );
237
    void exportDateScale( const Reference< beans::XPropertySet >& rAxisProps );
238
    void exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent );
239
240
    void exportSeries(
241
        const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram,
242
        const css::awt::Size & rPageSize,
243
        bool bExportContent,
244
        bool bHasTwoYAxes );
245
246
    void exportPropertyMapping(
247
        const css::uno::Reference< css::chart2::data::XDataSource > & xSource,
248
        const Sequence< OUString >& rSupportedMappings );
249
250
    void exportCandleStickSeries(
251
        const css::uno::Sequence<
252
            css::uno::Reference< css::chart2::XDataSeries > > & aSeriesSeq,
253
        const css::uno::Reference< css::chart2::XDiagram > & xDiagram,
254
        bool bJapaneseCandleSticks,
255
        bool bExportContent );
256
    void exportDataPoints(
257
        const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties,
258
        sal_Int32 nSeriesLength,
259
        const css::uno::Reference< css::chart2::XDiagram > & xDiagram,
260
        bool bExportContent );
261
262
    void exportCustomLabel(const SchXMLDataPointStruct& rPoint);
263
    void exportCustomLabelPosition(const chart2::RelativePosition& xCustomLabelPosition);
264
265
    void exportRegressionCurve(
266
        const css::uno::Reference<css::chart2::XDataSeries>& xSeries,
267
        const css::awt::Size& rPageSize,
268
        bool bExportContent );
269
270
    void exportErrorBar (
271
        const css::uno::Reference<beans::XPropertySet> &xSeriesProp, bool bYError,
272
            bool bExportContent );
273
274
    /// add svg position as attribute for current element
275
    void addPosition( const css::awt::Point & rPosition );
276
    void addPosition( const css::uno::Reference< css::drawing::XShape >& xShape );
277
    /// add svg size as attribute for current element
278
    void addSize( const css::awt::Size & rSize, bool bIsOOoNamespace = false );
279
    void addSize( const css::uno::Reference< css::drawing::XShape >& xShape );
280
    /// exports a string as a paragraph element
281
    void exportText( const OUString& rText );
282
    void exportFormattedText( const css::uno::Reference< beans::XPropertySet >& xTitleProps );
283
284
public:
285
    SvXMLExport& mrExport;
286
    SvXMLAutoStylePoolP& mrAutoStylePool;
287
    rtl::Reference< XMLPropertySetMapper > mxPropertySetMapper;
288
    rtl::Reference< XMLChartExportPropertyMapper > mxExpPropMapper;
289
290
    static constexpr OUString gsTableName = u"local-table"_ustr;
291
    OUStringBuffer msStringBuffer;
292
    OUString msString;
293
294
    // members filled by InitRangeSegmentationProperties (retrieved from DataProvider)
295
    bool mbHasCategoryLabels; //if the categories are only automatically generated this will be false
296
    bool mbRowSourceColumns;
297
    OUString msChartAddress;
298
    css::uno::Sequence< sal_Int32 > maSequenceMapping;
299
300
    OUString msCLSID;
301
302
    OUString maSrcShellID;
303
    OUString maDestShellID;
304
305
    css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes;
306
307
    tDataSequenceCont m_aDataSequencesToExport;
308
    OUString maCategoriesRange;
309
};
310
311
namespace
312
{
313
CustomLabelData lcl_getCustomLabelField(SvXMLExport const& rExport,
314
                                       sal_Int32 nDataPointIndex,
315
                                       const uno::Reference< chart2::XDataSeries >& rSeries)
316
0
{
317
0
    if (!rSeries.is())
318
0
        return CustomLabelData();
319
320
    // Custom data label text will be written to the <text:p> child element of a
321
    // <chart:data-label> element. That exists only since ODF 1.2.
322
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
323
0
        rExport.getSaneDefaultVersion());
324
0
    if (nCurrentODFVersion < SvtSaveOptions::ODFSVER_012)
325
0
        return CustomLabelData();
326
327
0
    if(Reference<beans::XPropertySet> xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is())
328
0
    {
329
0
        if(Any aAny = xLabels->getPropertyValue(u"CustomLabelFields"_ustr); aAny.hasValue())
330
0
        {
331
0
            CustomLabelData aData;
332
0
            Sequence<uno::Reference<chart2::XDataPointCustomLabelField>> aCustomLabels;
333
0
            aAny >>= aCustomLabels;
334
0
            for (const auto& rField : aCustomLabels)
335
0
            {
336
0
                if (rField->getFieldType() == chart2::DataPointCustomLabelFieldType_CELLRANGE)
337
0
                {
338
0
                    if (rField->getDataLabelsRange())
339
0
                        aData.mbDataLabelsRange = true;
340
0
                    aData.maRange = rField->getCellRange();
341
0
                    aData.maGuid = rField->getGuid();
342
0
                }
343
0
            }
344
345
0
            aData.maFields = std::move(aCustomLabels);
346
0
            return aData;
347
0
        }
348
0
    }
349
0
    return CustomLabelData();
350
0
}
351
352
css::chart2::RelativePosition lcl_getCustomLabelPosition(
353
    SvXMLExport const& rExport,
354
    sal_Int32 const nDataPointIndex,
355
    const uno::Reference< chart2::XDataSeries >& rSeries)
356
0
{
357
0
    if (!rSeries.is())
358
0
        return chart2::RelativePosition();
359
360
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
361
0
        rExport.getSaneDefaultVersion());
362
363
0
    if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) // do not export to ODF 1.3 or older
364
0
        return chart2::RelativePosition();
365
366
0
    if (Reference<beans::XPropertySet> xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is())
367
0
    {
368
0
        if (Any aAny = xLabels->getPropertyValue(u"CustomLabelPosition"_ustr); aAny.hasValue())
369
0
        {
370
0
            chart2::RelativePosition aCustomLabelPos;
371
0
            aAny >>= aCustomLabelPos;
372
0
            return aCustomLabelPos;
373
0
        }
374
0
    }
375
0
    return chart2::RelativePosition();
376
0
}
377
378
class lcl_MatchesRole
379
{
380
public:
381
    explicit lcl_MatchesRole( OUString aRole ) :
382
0
            m_aRole(std::move( aRole ))
383
0
    {}
384
385
    bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
386
0
    {
387
0
        if( !xSeq.is() )
388
0
            return  false;
389
0
        Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
390
0
        OUString aRole;
391
392
0
        return ( xProp.is() &&
393
0
                 (xProp->getPropertyValue( u"Role"_ustr ) >>= aRole ) &&
394
0
                 m_aRole == aRole );
395
0
    }
396
397
private:
398
    OUString m_aRole;
399
};
400
401
Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram )
402
0
{
403
0
    Reference< chart2::data::XLabeledDataSequence >  xResult;
404
0
    try
405
0
    {
406
0
        Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
407
0
            xDiagram, uno::UNO_QUERY_THROW );
408
0
        const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
409
0
            xCooSysCnt->getCoordinateSystems());
410
0
        for( const auto& rCooSys : aCooSysSeq )
411
0
        {
412
0
            Reference< chart2::XCoordinateSystem > xCooSys( rCooSys );
413
0
            SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL" );
414
0
            for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
415
0
            {
416
0
                const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
417
0
                for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
418
0
                {
419
0
                    Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI );
420
0
                    SAL_WARN_IF( !xAxis.is(), "xmloff.chart", "xAxis is NULL");
421
0
                    if( xAxis.is())
422
0
                    {
423
0
                        chart2::ScaleData aScaleData = xAxis->getScaleData();
424
0
                        if( aScaleData.Categories.is())
425
0
                        {
426
0
                            xResult.set( aScaleData.Categories );
427
0
                            break;
428
0
                        }
429
0
                    }
430
0
                }
431
0
            }
432
0
        }
433
0
    }
434
0
    catch( const uno::Exception & )
435
0
    {
436
0
        DBG_UNHANDLED_EXCEPTION("xmloff.chart");
437
0
    }
438
439
0
    return xResult;
440
0
}
441
442
Reference< chart2::data::XDataSource > lcl_createDataSource(
443
    const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData )
444
0
{
445
0
    const Reference< uno::XComponentContext >& xContext(
446
0
        comphelper::getProcessComponentContext() );
447
0
    Reference< chart2::data::XDataSink > xSink(
448
0
        xContext->getServiceManager()->createInstanceWithContext(
449
0
            u"com.sun.star.chart2.data.DataSource"_ustr, xContext ),
450
0
        uno::UNO_QUERY_THROW );
451
0
    xSink->setData( aData );
452
453
0
    return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY );
454
0
}
455
456
Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc )
457
0
{
458
0
    ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer;
459
0
    if( xChartDoc.is() )
460
0
    {
461
0
        Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
462
0
        ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram ));
463
0
        for( const auto& rSeries : aSeriesVector )
464
0
        {
465
0
            Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY );
466
0
            if( !xDataSource.is() )
467
0
                continue;
468
0
            const uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() );
469
0
            aContainer.insert( aContainer.end(), aDataSequences.begin(), aDataSequences.end() );
470
0
        }
471
0
    }
472
473
0
    return comphelper::containerToSequence( aContainer );
474
0
}
475
476
Reference< chart2::data::XLabeledDataSequence >
477
    lcl_getDataSequenceByRole(
478
        const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq,
479
        const OUString & rRole )
480
0
{
481
0
    Reference< chart2::data::XLabeledDataSequence > aNoResult;
482
483
0
    const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
484
0
    const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
485
0
    const Reference< chart2::data::XLabeledDataSequence > * pMatch =
486
0
        ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole ));
487
488
0
    if( pMatch != pEnd )
489
0
        return *pMatch;
490
491
0
    return aNoResult;
492
0
}
493
494
Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, bool& rOutSourceHasCategoryLabels )
495
0
{
496
0
    ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector;
497
498
    //categories are always the first sequence
499
0
    Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
500
0
    Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) );
501
0
    if( xCategories.is() )
502
0
        aLabeledSeqVector.push_back( xCategories );
503
0
    rOutSourceHasCategoryLabels = xCategories.is();
504
505
0
    const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector(
506
0
            lcl_getAllSeriesSequences( xChartDoc ) );
507
508
    //the first x-values is always the next sequence //todo ... other x-values get lost for old format
509
0
    Reference< chart2::data::XLabeledDataSequence > xXValues(
510
0
        lcl_getDataSequenceByRole( aSeriesSeqVector, u"values-x"_ustr ) );
511
0
    if( xXValues.is() )
512
0
        aLabeledSeqVector.push_back( xXValues );
513
514
    //add all other sequences now without x-values
515
0
    lcl_MatchesRole aHasXValues( u"values-x"_ustr );
516
0
    std::ranges::copy_if(aSeriesSeqVector, std::back_inserter(aLabeledSeqVector),
517
0
                 [&aHasXValues](const auto& rSeriesSeq) { return !aHasXValues( rSeriesSeq ); });
518
519
0
    Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( comphelper::containerToSequence(aLabeledSeqVector) );
520
521
0
    return lcl_createDataSource( aSeq );
522
0
}
523
524
bool lcl_isSeriesAttachedToFirstAxis(
525
    const Reference< chart2::XDataSeries > & xDataSeries )
526
0
{
527
0
    bool bResult=true;
528
529
0
    try
530
0
    {
531
0
        sal_Int32 nAxisIndex = 0;
532
0
        Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
533
0
        xProp->getPropertyValue(u"AttachedAxisIndex"_ustr) >>= nAxisIndex;
534
0
        bResult = (0==nAxisIndex);
535
0
    }
536
0
    catch( const uno::Exception & )
537
0
    {
538
0
        DBG_UNHANDLED_EXCEPTION("xmloff.chart");
539
0
    }
540
541
0
    return bResult;
542
0
}
543
544
OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::XChartDocument > & xDoc )
545
0
{
546
0
    OUString aResult = rRange;
547
0
    if( !xDoc.is() )
548
0
        return aResult;
549
0
    Reference< chart2::data::XRangeXMLConversion > xConversion(
550
0
        xDoc->getDataProvider(), uno::UNO_QUERY );
551
0
    if( xConversion.is())
552
0
        aResult = xConversion->convertRangeToXML( rRange );
553
0
    return aResult;
554
0
}
555
556
typedef ::std::pair< OUString, OUString > tLabelAndValueRange;
557
558
tLabelAndValueRange lcl_getLabelAndValueRangeByRole(
559
    const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt,
560
    const OUString & rRole,
561
    const Reference< chart2::XChartDocument > & xDoc,
562
    SchXMLExportHelper_Impl::tDataSequenceCont & rOutSequencesToExport )
563
0
{
564
0
    tLabelAndValueRange aResult;
565
566
0
    Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
567
0
        lcl_getDataSequenceByRole( aSeqCnt, rRole ));
568
0
    if( xLabeledSeq.is())
569
0
    {
570
0
        Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
571
0
        if( xLabelSeq.is())
572
0
            aResult.first = lcl_ConvertRange( xLabelSeq->getSourceRangeRepresentation(), xDoc );
573
574
0
        Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
575
0
        if( xValueSeq.is())
576
0
            aResult.second = lcl_ConvertRange( xValueSeq->getSourceRangeRepresentation(), xDoc );
577
578
0
        if( xLabelSeq.is() || xValueSeq.is())
579
0
            rOutSequencesToExport.emplace_back( xLabelSeq, xValueSeq );
580
0
    }
581
582
0
    return aResult;
583
0
}
584
585
sal_Int32 lcl_getSequenceLengthByRole(
586
    const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt,
587
    const OUString & rRole )
588
0
{
589
0
    Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
590
0
        lcl_getDataSequenceByRole( aSeqCnt, rRole ));
591
0
    if( xLabeledSeq.is())
592
0
    {
593
0
        Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getValues());
594
0
        return xSeq->getData().getLength();
595
0
    }
596
0
    return 0;
597
0
}
598
599
OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
600
0
{
601
0
    OUStringBuffer aResult;
602
0
    bool bPrecedeWithSpace = false;
603
0
    for( const auto& rString : rSequence )
604
0
    {
605
0
        if( !rString.isEmpty())
606
0
        {
607
0
            if( bPrecedeWithSpace )
608
0
                aResult.append( ' ' );
609
0
            aResult.append( rString );
610
0
            bPrecedeWithSpace = true;
611
0
        }
612
0
    }
613
0
    return aResult.makeStringAndClear();
614
0
}
615
616
void lcl_getLabelStringSequence( Sequence< OUString >& rOutLabels, const Reference< chart2::data::XDataSequence > & xLabelSeq )
617
0
{
618
0
    uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY );
619
0
    if( xTextualDataSequence.is())
620
0
    {
621
0
        rOutLabels = xTextualDataSequence->getTextualData();
622
0
    }
623
0
    else if( xLabelSeq.is())
624
0
    {
625
0
        Sequence< uno::Any > aAnies( xLabelSeq->getData());
626
0
        rOutLabels.realloc( aAnies.getLength());
627
0
        auto pOutLabels = rOutLabels.getArray();
628
0
        for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
629
0
            aAnies[i] >>= pOutLabels[i];
630
0
    }
631
0
}
632
633
sal_Int32 lcl_getMaxSequenceLength(
634
    const SchXMLExportHelper_Impl::tDataSequenceCont & rContainer )
635
0
{
636
0
    sal_Int32 nResult = 0;
637
0
    for( const auto& rDataSequence : rContainer )
638
0
    {
639
0
        if( rDataSequence.second.is())
640
0
        {
641
0
            sal_Int32 nSeqLength = rDataSequence.second->getData().getLength();
642
0
            if( nSeqLength > nResult )
643
0
                nResult = nSeqLength;
644
0
        }
645
0
    }
646
0
    return nResult;
647
0
}
648
649
uno::Sequence< OUString > lcl_DataSequenceToStringSequence(
650
    const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
651
0
{
652
0
    uno::Sequence< OUString > aResult;
653
0
    if(!xDataSequence.is())
654
0
        return aResult;
655
656
0
    uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY );
657
0
    if( xTextualDataSequence.is() )
658
0
    {
659
0
        aResult = xTextualDataSequence->getTextualData();
660
0
    }
661
0
    else
662
0
    {
663
0
        uno::Sequence< uno::Any > aValues = xDataSequence->getData();
664
0
        aResult.realloc(aValues.getLength());
665
0
        auto pResult = aResult.getArray();
666
667
0
        for(sal_Int32 nN=aValues.getLength();nN--;)
668
0
            aValues[nN] >>= pResult[nN];
669
0
    }
670
671
0
    return aResult;
672
0
}
673
::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq )
674
0
{
675
0
    ::std::vector< double > aResult;
676
0
    if(!xSeq.is())
677
0
        return aResult;
678
679
0
    uno::Sequence< double > aValuesSequence;
680
0
    Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
681
0
    if( xNumSeq.is() )
682
0
    {
683
0
        aValuesSequence = xNumSeq->getNumericalData();
684
0
    }
685
0
    else
686
0
    {
687
0
        Sequence< uno::Any > aAnies( xSeq->getData() );
688
0
        aValuesSequence.realloc( aAnies.getLength() );
689
0
        auto pValuesSequence = aValuesSequence.getArray();
690
0
        for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
691
0
            aAnies[i] >>= pValuesSequence[i];
692
0
    }
693
694
    //special handling for x-values (if x-values do point to categories, indices are used instead )
695
0
    Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY );
696
0
    if( xProp.is() )
697
0
    {
698
0
        OUString aRole;
699
0
        xProp->getPropertyValue(u"Role"_ustr) >>= aRole;
700
0
        if( aRole.match("values-x") )
701
0
        {
702
            //lcl_clearIfNoValuesButTextIsContained - replace by indices if the values are not appropriate
703
0
            bool bHasValue = std::any_of(std::cbegin(aValuesSequence), std::cend(aValuesSequence),
704
0
                [](double fValue) { return !std::isnan( fValue ); });
705
0
            if(!bHasValue)
706
0
            {
707
                //no double value is contained
708
                //is there any text?
709
0
                const uno::Sequence< OUString > aStrings( lcl_DataSequenceToStringSequence( xSeq ) );
710
0
                bool bHasText = std::any_of(aStrings.begin(), aStrings.end(),
711
0
                    [](const OUString& rString) { return !rString.isEmpty(); });
712
0
                if( bHasText )
713
0
                {
714
0
                    auto [begin, end] = asNonConstRange(aValuesSequence);
715
0
                    std::iota(begin, end, 1);
716
0
                }
717
0
            }
718
0
        }
719
0
    }
720
721
0
    aResult.insert( aResult.end(), std::cbegin(aValuesSequence), std::cend(aValuesSequence) );
722
0
    return aResult;
723
0
}
724
725
bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
726
0
{
727
0
    if( !xDataSequence.is() )
728
0
        return false;
729
0
    uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY );
730
0
    if( xProp.is() )
731
0
    {
732
0
        uno::Sequence< sal_Int32 > aHiddenValues;
733
0
        try
734
0
        {
735
0
            xProp->getPropertyValue(u"HiddenValues"_ustr) >>= aHiddenValues;
736
0
            if( !aHiddenValues.hasElements() )
737
0
                return true;
738
0
        }
739
0
        catch( const uno::Exception& )
740
0
        {
741
0
            return true;
742
0
        }
743
0
    }
744
0
    return xDataSequence->getData().hasElements();
745
0
}
746
747
typedef vector< OUString > tStringVector;
748
typedef vector< vector< double > > t2DNumberContainer;
749
750
struct lcl_TableData
751
{
752
    t2DNumberContainer  aDataInRows;
753
    tStringVector       aDataRangeRepresentations;
754
755
    tStringVector       aColumnDescriptions;
756
    tStringVector       aColumnDescriptions_Ranges;
757
758
    tStringVector       aRowDescriptions;
759
    tStringVector       aRowDescriptions_Ranges;
760
761
    Sequence< Sequence< uno::Any > >    aComplexColumnDescriptions;//outer index is columns - inner index is level
762
    Sequence< Sequence< uno::Any > >    aComplexRowDescriptions;//outer index is rows - inner index is level
763
764
    ::std::vector< sal_Int32 > aHiddenColumns;
765
};
766
767
typedef ::std::map< sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair >
768
    lcl_DataSequenceMap;
769
770
struct lcl_SequenceToMapElement
771
{
772
    std::pair<const sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair>
773
        operator() (const SchXMLExportHelper_Impl::tLabelValuesDataPair& rContent)
774
0
    {
775
0
        sal_Int32 nIndex = -1;
776
0
        if( rContent.second.is()) //has values
777
0
        {
778
0
            OUString aRangeRep( rContent.second->getSourceRangeRepresentation());
779
0
            nIndex = aRangeRep.toInt32();
780
0
        }
781
0
        else if( rContent.first.is()) //has labels
782
0
            nIndex = o3tl::toInt32(rContent.first->getSourceRangeRepresentation().subView( sizeof("label ")));
783
0
        return std::make_pair(nIndex, rContent);
784
0
    }
785
};
786
787
void lcl_ReorderInternalSequencesAccordingToTheirRangeName(
788
    SchXMLExportHelper_Impl::tDataSequenceCont & rInOutSequences )
789
0
{
790
0
    lcl_DataSequenceMap aIndexSequenceMap;
791
0
    ::std::transform( rInOutSequences.begin(), rInOutSequences.end(),
792
0
                      ::std::inserter( aIndexSequenceMap, aIndexSequenceMap.begin()),
793
0
                      lcl_SequenceToMapElement());
794
795
0
    rInOutSequences.clear();
796
0
    sal_Int32 nIndex = 0;
797
0
    for( const auto& rEntry : aIndexSequenceMap )
798
0
    {
799
0
        if( rEntry.first >= 0 )
800
0
        {
801
            // fill empty columns
802
0
            rInOutSequences.insert(
803
0
                    rInOutSequences.end(),
804
0
                    rEntry.first - nIndex,
805
0
                    SchXMLExportHelper_Impl::tDataSequenceCont::value_type(
806
0
                        uno::Reference< chart2::data::XDataSequence >(),
807
0
                        uno::Reference< chart2::data::XDataSequence >() ));
808
0
            nIndex = rEntry.first;
809
0
            rInOutSequences.push_back( rEntry.second );
810
0
        }
811
812
0
        ++nIndex;
813
0
    }
814
0
}
815
816
lcl_TableData lcl_getDataForLocalTable(
817
    const SchXMLExportHelper_Impl::tDataSequenceCont & aSequencesToExport,
818
    const Reference< chart2::XAnyDescriptionAccess >& xAnyDescriptionAccess,
819
    const OUString& rCategoriesRange,
820
    bool bSeriesFromColumns,
821
    const Reference< chart2::data::XRangeXMLConversion > & xRangeConversion )
822
0
{
823
0
    lcl_TableData aResult;
824
825
0
    try
826
0
    {
827
0
        Sequence< OUString > aSimpleCategories;
828
0
        if( xAnyDescriptionAccess.is() )
829
0
        {
830
            //categories
831
0
            if( bSeriesFromColumns )
832
0
            {
833
0
                aSimpleCategories = xAnyDescriptionAccess->getRowDescriptions();
834
0
                aResult.aComplexRowDescriptions = xAnyDescriptionAccess->getAnyRowDescriptions();
835
0
            }
836
0
            else
837
0
            {
838
0
                aSimpleCategories = xAnyDescriptionAccess->getColumnDescriptions();
839
0
                aResult.aComplexColumnDescriptions = xAnyDescriptionAccess->getAnyColumnDescriptions();
840
0
            }
841
0
        }
842
843
        //series values and series labels
844
0
        SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences = aSequencesToExport.size();
845
846
0
        auto nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport ));
847
0
        if( aSimpleCategories.getLength() > nMaxSequenceLength )
848
0
        {
849
0
            aSimpleCategories.realloc(nMaxSequenceLength);//#i110617#
850
0
        }
851
0
        size_t nNumColumns( bSeriesFromColumns ? nNumSequences : nMaxSequenceLength );
852
0
        size_t nNumRows( bSeriesFromColumns ? nMaxSequenceLength : nNumSequences );
853
854
        // resize data
855
0
        aResult.aDataInRows.resize( nNumRows );
856
857
0
        for (auto& aData: aResult.aDataInRows)
858
0
            aData.resize(nNumColumns, std::numeric_limits<double>::quiet_NaN());
859
0
        aResult.aColumnDescriptions.resize( nNumColumns );
860
0
        aResult.aComplexColumnDescriptions.realloc( nNumColumns );
861
0
        aResult.aRowDescriptions.resize( nNumRows );
862
0
        aResult.aComplexRowDescriptions.realloc( nNumRows );
863
864
0
        tStringVector& rCategories = bSeriesFromColumns ? aResult.aRowDescriptions    : aResult.aColumnDescriptions;
865
0
        tStringVector& rLabels     = bSeriesFromColumns ? aResult.aColumnDescriptions : aResult.aRowDescriptions;
866
867
        //categories
868
0
        rCategories.clear();
869
0
        rCategories.insert( rCategories.begin(), std::cbegin(aSimpleCategories), std::cend(aSimpleCategories) );
870
0
        if( !rCategoriesRange.isEmpty() )
871
0
        {
872
0
            OUString aRange(rCategoriesRange);
873
0
            if( xRangeConversion.is())
874
0
                aRange = xRangeConversion->convertRangeToXML( aRange );
875
0
            if( bSeriesFromColumns )
876
0
                aResult.aRowDescriptions_Ranges.push_back( aRange );
877
0
            else
878
0
                aResult.aColumnDescriptions_Ranges.push_back( aRange );
879
0
        }
880
881
        // iterate over all sequences
882
0
        size_t nSeqIdx = 0;
883
0
        Sequence< Sequence< OUString > > aComplexLabels(nNumSequences);
884
0
        auto aComplexLabelsRange = asNonConstRange(aComplexLabels);
885
0
        for( const auto& rDataSequence : aSequencesToExport )
886
0
        {
887
0
            OUString aRange;
888
0
            Sequence< OUString >& rCurrentComplexLabel = aComplexLabelsRange[nSeqIdx];
889
0
            if( rDataSequence.first.is())
890
0
            {
891
0
                lcl_getLabelStringSequence( rCurrentComplexLabel, rDataSequence.first );
892
0
                rLabels[nSeqIdx] = lcl_flattenStringSequence( rCurrentComplexLabel );
893
0
                aRange = rDataSequence.first->getSourceRangeRepresentation();
894
0
                if( xRangeConversion.is())
895
0
                    aRange = xRangeConversion->convertRangeToXML( aRange );
896
0
            }
897
0
            else if( rDataSequence.second.is())
898
0
            {
899
0
                rCurrentComplexLabel.realloc(1);
900
0
                rLabels[nSeqIdx] = rCurrentComplexLabel.getArray()[0] = lcl_flattenStringSequence(
901
0
                    rDataSequence.second->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE ));
902
0
            }
903
0
            if( bSeriesFromColumns )
904
0
                aResult.aColumnDescriptions_Ranges.push_back( aRange );
905
0
            else
906
0
                aResult.aRowDescriptions_Ranges.push_back( aRange );
907
908
0
            ::std::vector< double > aNumbers( lcl_getAllValuesFromSequence( rDataSequence.second ));
909
0
            if( bSeriesFromColumns )
910
0
            {
911
0
                const sal_Int32 nSize( static_cast< sal_Int32 >( aNumbers.size()));
912
0
                for( sal_Int32 nIdx=0; nIdx<nSize; ++nIdx )
913
0
                    aResult.aDataInRows[nIdx][nSeqIdx] = aNumbers[nIdx];
914
0
            }
915
0
            else
916
0
                aResult.aDataInRows[nSeqIdx] = std::move(aNumbers);
917
918
0
            if( rDataSequence.second.is())
919
0
            {
920
0
                aRange =  rDataSequence.second->getSourceRangeRepresentation();
921
0
                if( xRangeConversion.is())
922
0
                    aRange = xRangeConversion->convertRangeToXML( aRange );
923
0
            }
924
0
            aResult.aDataRangeRepresentations.push_back( aRange );
925
926
            //is column hidden?
927
0
            if( !lcl_SequenceHasUnhiddenData(rDataSequence.first) && !lcl_SequenceHasUnhiddenData(rDataSequence.second) )
928
0
                aResult.aHiddenColumns.push_back(nSeqIdx);
929
930
0
            ++nSeqIdx;
931
0
        }
932
0
        Sequence< Sequence< Any > >& rComplexAnyLabels = bSeriesFromColumns ? aResult.aComplexColumnDescriptions : aResult.aComplexRowDescriptions;//#i116544#
933
0
        rComplexAnyLabels.realloc(aComplexLabels.getLength());
934
0
        auto pComplexAnyLabels = rComplexAnyLabels.getArray();
935
0
        for( sal_Int32 nN=0; nN<aComplexLabels.getLength();nN++ )
936
0
        {
937
0
            Sequence< OUString >& rSource = aComplexLabelsRange[nN];
938
0
            Sequence< Any >& rTarget = pComplexAnyLabels[nN];
939
0
            rTarget.realloc( rSource.getLength() );
940
0
            auto pTarget = rTarget.getArray();
941
0
            for( sal_Int32 i=0; i<rSource.getLength(); i++ )
942
0
                pTarget[i] <<= rSource[i];
943
0
        }
944
0
    }
945
0
    catch( const uno::Exception & )
946
0
    {
947
0
        TOOLS_INFO_EXCEPTION("xmloff.chart", "something went wrong during table data collection");
948
0
    }
949
950
0
    return aResult;
951
0
}
952
953
void lcl_exportNumberFormat( const OUString& rPropertyName, const Reference< beans::XPropertySet >& xPropSet,
954
                                        SvXMLExport& rExport )
955
0
{
956
0
    if( xPropSet.is())
957
0
    {
958
0
        sal_Int32 nNumberFormat = 0;
959
0
        Any aNumAny = xPropSet->getPropertyValue( rPropertyName );
960
0
        if( (aNumAny >>= nNumberFormat) && (nNumberFormat != -1) )
961
0
            rExport.addDataStyle( nNumberFormat );
962
0
    }
963
0
}
964
965
::std::vector< Reference< chart2::data::XDataSequence > >
966
    lcl_getErrorBarSequences( const Reference< beans::XPropertySet > & xErrorBarProp )
967
0
{
968
0
    ::std::vector< Reference< chart2::data::XDataSequence > > aResult;
969
0
    Reference< chart2::data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY );
970
0
    if( !xErrorBarDataSource.is())
971
0
        return aResult;
972
973
0
    const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences(
974
0
        xErrorBarDataSource->getDataSequences());
975
0
    for( const auto& rSequence : aSequences )
976
0
    {
977
0
        try
978
0
        {
979
0
            if( rSequence.is())
980
0
            {
981
0
                Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues());
982
0
                Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
983
0
                OUString aRole;
984
0
                if( ( xSeqProp->getPropertyValue( u"Role"_ustr ) >>= aRole ) &&
985
0
                    aRole.match( "error-bars-" ))
986
0
                {
987
0
                    aResult.push_back( xSequence );
988
0
                }
989
0
            }
990
0
        }
991
0
        catch( const uno::Exception & )
992
0
        {
993
0
            TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exporting error bar ranges" );
994
0
        }
995
0
    }
996
997
0
    return aResult;
998
0
}
999
1000
bool lcl_exportDomainForThisSequence( const Reference< chart2::data::XDataSequence >& rValues, OUString& rFirstRangeForThisDomainIndex, SvXMLExport& rExport )
1001
0
{
1002
0
    bool bDomainExported = false;
1003
0
    if( rValues.is())
1004
0
    {
1005
0
        Reference< chart2::XChartDocument > xNewDoc( rExport.GetModel(), uno::UNO_QUERY );
1006
0
        OUString aRange( lcl_ConvertRange( rValues->getSourceRangeRepresentation(), xNewDoc ) );
1007
1008
        //work around error in OOo 2.0 (problems with multiple series having a domain element)
1009
0
        if( rFirstRangeForThisDomainIndex.isEmpty() || aRange != rFirstRangeForThisDomainIndex )
1010
0
        {
1011
0
            rExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, aRange);
1012
0
            SvXMLElementExport aDomain( rExport, XML_NAMESPACE_CHART, XML_DOMAIN, true, true );
1013
0
            bDomainExported = true;
1014
0
        }
1015
1016
0
        if( rFirstRangeForThisDomainIndex.isEmpty() )
1017
0
            rFirstRangeForThisDomainIndex = aRange;
1018
0
    }
1019
0
    return bDomainExported;
1020
0
}
1021
1022
} // anonymous namespace
1023
1024
1025
SchXMLExportHelper::SchXMLExportHelper( SvXMLExport& rExport, SvXMLAutoStylePoolP& rASPool )
1026
0
    : m_pImpl( new SchXMLExportHelper_Impl( rExport, rASPool ) )
1027
0
{
1028
0
}
1029
1030
SchXMLExportHelper::~SchXMLExportHelper()
1031
0
{
1032
0
}
1033
1034
const OUString& SchXMLExportHelper::getChartCLSID() const
1035
0
{
1036
0
    return m_pImpl->msCLSID;
1037
0
}
1038
1039
void SchXMLExportHelper::SetSourceShellID( const OUString& rShellID )
1040
0
{
1041
0
    m_pImpl->maSrcShellID = rShellID;
1042
0
}
1043
1044
void SchXMLExportHelper::SetDestinationShellID( const OUString& rShellID )
1045
0
{
1046
0
    m_pImpl->maDestShellID = rShellID;
1047
0
}
1048
1049
const rtl::Reference< XMLPropertySetMapper >& SchXMLExportHelper_Impl::GetPropertySetMapper() const
1050
0
{
1051
0
    return mxPropertySetMapper;
1052
0
}
1053
1054
void SchXMLExportHelper_Impl::exportAutoStyles()
1055
0
{
1056
0
    if( !mxExpPropMapper.is())
1057
0
        return;
1058
1059
    //ToDo: when embedded in calc/writer this is not necessary because the
1060
    // numberformatter is shared between both documents
1061
0
    mrExport.exportAutoDataStyles();
1062
1063
    // export chart auto styles
1064
0
    mrAutoStylePool.exportXML( XmlStyleFamily::SCH_CHART_ID );
1065
1066
    // export auto styles for additional shapes
1067
0
    mrExport.GetShapeExport()->exportAutoStyles();
1068
    // and for text in additional shapes
1069
0
    mrExport.GetTextParagraphExport()->exportTextAutoStyles();
1070
0
}
1071
1072
// private methods
1073
1074
SchXMLExportHelper_Impl::SchXMLExportHelper_Impl(
1075
    SvXMLExport& rExport,
1076
    SvXMLAutoStylePoolP& rASPool ) :
1077
0
        mrExport( rExport ),
1078
0
        mrAutoStylePool( rASPool ),
1079
0
        mxPropertySetMapper( new XMLChartPropertySetMapper(&rExport) ),
1080
0
        mxExpPropMapper( new XMLChartExportPropertyMapper( mxPropertySetMapper, rExport ) ),
1081
0
        mbHasCategoryLabels( false ),
1082
0
        mbRowSourceColumns( true ),
1083
0
        msCLSID( SvGlobalName( SO3_SCH_CLASSID ).GetHexName() )
1084
0
{
1085
    // register chart auto-style family
1086
0
    mrAutoStylePool.AddFamily(
1087
0
        XmlStyleFamily::SCH_CHART_ID,
1088
0
        XML_STYLE_FAMILY_SCH_CHART_NAME,
1089
0
        mxExpPropMapper.get(),
1090
0
        XML_STYLE_FAMILY_SCH_CHART_PREFIX);
1091
1092
    // register shape family
1093
0
    mrAutoStylePool.AddFamily(
1094
0
        XmlStyleFamily::SD_GRAPHICS_ID,
1095
0
        XML_STYLE_FAMILY_SD_GRAPHICS_NAME,
1096
0
        mxExpPropMapper.get(),
1097
0
        XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX);
1098
    // register paragraph family also for shapes
1099
0
    mrAutoStylePool.AddFamily(
1100
0
        XmlStyleFamily::TEXT_PARAGRAPH,
1101
0
        GetXMLToken( XML_PARAGRAPH ),
1102
0
        mxExpPropMapper.get(),
1103
0
        OUString( 'P' ));
1104
    // register text family also for shapes
1105
0
    mrAutoStylePool.AddFamily(
1106
0
        XmlStyleFamily::TEXT_TEXT,
1107
0
        GetXMLToken( XML_TEXT ),
1108
0
        mxExpPropMapper.get(),
1109
0
        OUString( 'T' ));
1110
0
}
1111
1112
void SchXMLExportHelper_Impl::collectAutoStyles( Reference< chart::XChartDocument > const & rChartDoc )
1113
0
{
1114
0
    parseDocument( rChartDoc, false );
1115
0
}
1116
1117
void SchXMLExportHelper_Impl::exportChart( Reference< chart::XChartDocument > const & rChartDoc,
1118
                                      bool bIncludeTable )
1119
0
{
1120
0
    parseDocument( rChartDoc, true, bIncludeTable );
1121
0
    SAL_WARN_IF( !maAutoStyleNameQueue.empty(), "xmloff.chart", "There are still remaining autostyle names in the queue" );
1122
0
}
1123
1124
static OUString lcl_GetStringFromNumberSequence( const css::uno::Sequence< sal_Int32 >& rSequenceMapping, bool bRemoveOneFromEachIndex /*should be true if having categories*/ )
1125
0
{
1126
0
    OUStringBuffer aBuf;
1127
0
    bool bHasPredecessor = false;
1128
0
    for( sal_Int32 nIndex : rSequenceMapping )
1129
0
    {
1130
0
        if( bRemoveOneFromEachIndex )
1131
0
            --nIndex;
1132
0
        if(nIndex>=0)
1133
0
        {
1134
0
            if(bHasPredecessor)
1135
0
                aBuf.append( ' ' );
1136
0
            aBuf.append( nIndex );
1137
0
            bHasPredecessor = true;
1138
0
        }
1139
0
    }
1140
0
    return aBuf.makeStringAndClear();
1141
0
}
1142
1143
/// if bExportContent is false the auto-styles are collected
1144
void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > const & rChartDoc,
1145
                                        bool bExportContent,
1146
                                        bool bIncludeTable )
1147
0
{
1148
0
    Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY );
1149
0
    if( !rChartDoc.is() || !xNewDoc.is() )
1150
0
    {
1151
0
        SAL_WARN("xmloff.chart", "No XChartDocument was given for export." );
1152
0
        return;
1153
0
    }
1154
1155
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(mrExport.getSaneDefaultVersion());
1156
1157
0
    mxExpPropMapper->setChartDoc(xNewDoc);
1158
1159
0
    Reference< chart::XDiagram > xDiagram = rChartDoc->getDiagram();
1160
0
    Reference< chart2::XDiagram > xNewDiagram;
1161
0
    if( xNewDoc.is())
1162
0
        xNewDiagram.set( xNewDoc->getFirstDiagram());
1163
1164
    //todo remove if model changes are notified and view is updated automatically
1165
0
    if( bExportContent )
1166
0
    {
1167
0
        Reference< util::XRefreshable > xRefreshable( xNewDoc, uno::UNO_QUERY );
1168
0
        if( xRefreshable.is() )
1169
0
            xRefreshable->refresh();
1170
0
    }
1171
1172
    // get Properties of ChartDocument
1173
0
    bool bHasMainTitle = false;
1174
0
    bool bHasSubTitle = false;
1175
0
    bool bHasLegend = false;
1176
0
    util::DateTime aNullDate(0,0,0,0,30,12,1899, false);
1177
1178
0
    std::vector< XMLPropertyState > aPropertyStates;
1179
1180
0
    Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY );
1181
0
    if( xDocPropSet.is())
1182
0
    {
1183
0
        try
1184
0
        {
1185
0
            Any aAny = xDocPropSet->getPropertyValue(u"HasMainTitle"_ustr);
1186
0
            aAny >>= bHasMainTitle;
1187
0
            aAny = xDocPropSet->getPropertyValue(u"HasSubTitle"_ustr);
1188
0
            aAny >>= bHasSubTitle;
1189
0
            aAny = xDocPropSet->getPropertyValue(u"HasLegend"_ustr);
1190
0
            aAny >>= bHasLegend;
1191
0
            if ( bIncludeTable )
1192
0
            {
1193
0
                aAny = xDocPropSet->getPropertyValue(u"NullDate"_ustr);
1194
0
                if ( !aAny.hasValue() )
1195
0
                {
1196
0
                    Reference<container::XChild> xChild(rChartDoc, uno::UNO_QUERY );
1197
0
                    if ( xChild.is() )
1198
0
                    {
1199
0
                        Reference< beans::XPropertySet > xParentDoc( xChild->getParent(),uno::UNO_QUERY);
1200
0
                        if ( xParentDoc.is() && xParentDoc->getPropertySetInfo()->hasPropertyByName(u"NullDate"_ustr) )
1201
0
                            aAny = xParentDoc->getPropertyValue(u"NullDate"_ustr);
1202
0
                    }
1203
0
                }
1204
1205
0
                aAny >>= aNullDate;
1206
0
            }
1207
0
        }
1208
0
        catch( const beans::UnknownPropertyException & )
1209
0
        {
1210
0
            SAL_WARN("xmloff.chart", "Required property not found in ChartDocument" );
1211
0
        }
1212
0
    }
1213
1214
0
    if ( bIncludeTable && (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 ) )
1215
0
    {
1216
0
        assert(!mrExport.GetAttrList().getLength()); //must be empty before XML_CALCULATION_SETTINGS
1217
0
        SvXMLElementExport aSet( mrExport, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true );
1218
0
        {
1219
0
            OUStringBuffer sBuffer;
1220
0
            ::sax::Converter::convertDateTime(sBuffer, aNullDate, nullptr);
1221
0
            mrExport.AddAttribute( XML_NAMESPACE_TABLE,XML_DATE_VALUE,sBuffer.makeStringAndClear());
1222
0
            SvXMLElementExport aNull( mrExport, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true );
1223
0
        }
1224
0
    }
1225
1226
0
    awt::Size aPageSize( getPageSize( xNewDoc ));
1227
0
    if( bExportContent )
1228
0
        addSize( aPageSize );
1229
1230
    // chart element
1231
0
    std::unique_ptr<SvXMLElementExport> xElChart;
1232
1233
    // get property states for autostyles
1234
0
    if( mxExpPropMapper.is())
1235
0
    {
1236
0
        Reference< beans::XPropertySet > xPropSet = rChartDoc->getArea();
1237
0
        if( xPropSet.is())
1238
0
            aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
1239
0
    }
1240
1241
0
    if( bExportContent )
1242
0
    {
1243
        //export data provider in xlink:href attribute
1244
1245
0
        if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
1246
0
        {
1247
0
            OUString aDataProviderURL(  u".."_ustr  );
1248
0
            if( xNewDoc->hasInternalDataProvider() )
1249
0
                aDataProviderURL = ".";
1250
0
            else //special handling for data base data provider necessary
1251
0
            {
1252
0
                Reference< chart2::data::XDatabaseDataProvider > xDBDataProvider( xNewDoc->getDataProvider(), uno::UNO_QUERY );
1253
0
                if( xDBDataProvider.is() )
1254
0
                    aDataProviderURL = ".";
1255
0
            }
1256
0
            mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aDataProviderURL );
1257
0
            mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1258
0
        }
1259
1260
0
        chart2api::AbstractPivotTableDataProvider* pPivotTableDataProvider =
1261
0
            dynamic_cast<chart2api::AbstractPivotTableDataProvider*>(xNewDoc->getDataProvider().get());
1262
0
        if (pPivotTableDataProvider && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED)
1263
0
        {
1264
0
            OUString sPivotTableName = pPivotTableDataProvider->getPivotTableName();
1265
0
            mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, sPivotTableName);
1266
0
        }
1267
1268
0
        OUString sChartType( xDiagram->getDiagramType() );
1269
1270
        // attributes
1271
        // determine class
1272
0
        if( !sChartType.isEmpty())
1273
0
        {
1274
0
            enum XMLTokenEnum eXMLChartType = SchXMLTools::getTokenByChartType( sChartType, true /* bUseOldNames */ );
1275
1276
0
            SAL_WARN_IF( eXMLChartType == XML_TOKEN_INVALID, "xmloff.chart", "invalid chart class" );
1277
0
            if( eXMLChartType == XML_TOKEN_INVALID )
1278
0
                eXMLChartType = XML_BAR;
1279
1280
0
            if( eXMLChartType == XML_ADD_IN )
1281
0
            {
1282
                // sChartType is the service-name of the add-in
1283
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS,
1284
0
                                       mrExport.GetNamespaceMap().GetQNameByKey(
1285
0
                                           XML_NAMESPACE_OOO, sChartType) );
1286
0
            }
1287
0
            else if( eXMLChartType != XML_TOKEN_INVALID )
1288
0
            {
1289
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS,
1290
0
                        mrExport.GetNamespaceMap().GetQNameByKey(
1291
0
                            XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) );
1292
0
            }
1293
1294
0
            bool bIsOfPie = false;
1295
            // Handle subtype for of-pie charts
1296
0
            if (sChartType == u"com.sun.star.chart.BarOfPieDiagram") {
1297
0
                mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUB_BAR, OUString::boolean(true));
1298
0
                bIsOfPie = true;
1299
0
            } else if (sChartType == u"com.sun.star.chart.PieOfPieDiagram") {
1300
0
                mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUB_PIE, OUString::boolean(true));
1301
0
                bIsOfPie = true;
1302
0
            }
1303
1304
0
            if (bIsOfPie) {
1305
1306
                // Find the split position. We have to dig deep into the
1307
                // structure tree to get it, which is awkward. Part of the
1308
                // problem is that the split position is sort of a series-level
1309
                // parameter, but is generally handled at the chart level since
1310
                // of-pie charts have only a single series.
1311
0
                double fSplitPos = 2.0;
1312
1313
0
                Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY );
1314
0
                if (xBCooSysCnt.is()) {
1315
0
                    const Sequence< Reference< chart2::XCoordinateSystem > >
1316
0
                        aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
1317
0
                    for (const auto& rCooSys : aCooSysSeq ) {
1318
0
                        Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY );
1319
0
                        if( ! xCTCnt.is())
1320
0
                            continue;
1321
0
                        const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
1322
0
                        for (const auto& rChartType : aCTSeq ) {
1323
0
                            Reference< beans::XPropertySet > xCTProp( rChartType, uno::UNO_QUERY );
1324
1325
0
                            if (xCTProp.is()) {
1326
0
                                xCTProp->getPropertyValue(u"SplitPos"_ustr) >>= fSplitPos;
1327
0
                            }
1328
0
                        }
1329
0
                    }
1330
0
                }
1331
1332
                // Insert split position for of-pie chart
1333
0
                mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SPLIT_POSITION,
1334
0
                        OUString::number(fSplitPos));
1335
0
            }
1336
1337
            // The attribute table:cell-range-address was removed from the standard in ODF 1.4.
1338
            // The associated attributes chart:column-mapping and chart:row-mapping are deprecated.
1339
            //column-mapping or row-mapping
1340
0
            if( maSequenceMapping.hasElements() && nCurrentODFVersion < SvtSaveOptions::ODFSVER_014)
1341
0
            {
1342
0
                enum XMLTokenEnum eTransToken = ::xmloff::token::XML_ROW_MAPPING;
1343
0
                if( mbRowSourceColumns )
1344
0
                    eTransToken = ::xmloff::token::XML_COLUMN_MAPPING;
1345
0
                OUString aSequenceMappingStr( lcl_GetStringFromNumberSequence(
1346
0
                    maSequenceMapping, mbHasCategoryLabels && !xNewDoc->hasInternalDataProvider() ) );
1347
1348
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART,
1349
0
                                        ::xmloff::token::GetXMLToken( eTransToken ),
1350
0
                                        aSequenceMappingStr );
1351
0
            }
1352
0
        }
1353
        // write style name
1354
0
        AddAutoStyleAttribute( aPropertyStates );
1355
1356
        //element
1357
0
        xElChart.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_CHART, true, true ));
1358
0
    }
1359
0
    else    // autostyles
1360
0
    {
1361
0
        CollectAutoStyle( std::move(aPropertyStates) );
1362
0
    }
1363
    // remove property states for autostyles
1364
0
    aPropertyStates.clear();
1365
1366
    // title element
1367
0
    if( bHasMainTitle )
1368
0
    {
1369
        // get property states for autostyles
1370
0
        Reference< drawing::XShape > xShape = rChartDoc->getTitle();
1371
0
        Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
1372
0
        if( mxExpPropMapper.is() && xPropSet.is())
1373
0
        {
1374
0
            aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
1375
0
        }
1376
0
        if( bExportContent )
1377
0
        {
1378
0
            if( xShape.is())    // && "hasTitleBeenMoved"
1379
0
                addPosition( xShape );
1380
1381
            // write style name
1382
0
            AddAutoStyleAttribute( aPropertyStates );
1383
1384
            // element
1385
0
            SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true );
1386
1387
            // content (text:p)
1388
0
            exportFormattedText(xPropSet);
1389
0
        }
1390
0
        else    // autostyles
1391
0
        {
1392
0
            CollectAutoStyle( std::move(aPropertyStates) );
1393
0
            CollectAutoTextStyle( xPropSet );
1394
0
        }
1395
        // remove property states for autostyles
1396
0
        aPropertyStates.clear();
1397
0
    }
1398
1399
    // subtitle element
1400
0
    if( bHasSubTitle )
1401
0
    {
1402
        // get property states for autostyles
1403
0
        Reference< drawing::XShape > xShape = rChartDoc->getSubTitle();
1404
0
        Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
1405
0
        if( mxExpPropMapper.is() && xPropSet.is())
1406
0
        {
1407
0
            aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
1408
0
        }
1409
1410
0
        if( bExportContent )
1411
0
        {
1412
0
            if( xShape.is())
1413
0
                addPosition( xShape );
1414
1415
            // write style name
1416
0
            AddAutoStyleAttribute( aPropertyStates );
1417
1418
            // element (has no subelements)
1419
0
            SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, true, true );
1420
1421
            // content (text:p)
1422
0
            exportFormattedText(xPropSet);
1423
0
        }
1424
0
        else    // autostyles
1425
0
        {
1426
0
            CollectAutoStyle( std::move(aPropertyStates) );
1427
0
            CollectAutoTextStyle(xPropSet);
1428
0
        }
1429
        // remove property states for autostyles
1430
0
        aPropertyStates.clear();
1431
0
    }
1432
1433
    // legend element
1434
0
    if( bHasLegend )
1435
0
    {
1436
        // get property states for autostyles
1437
0
        if( mxExpPropMapper.is())
1438
0
        {
1439
0
            Reference< beans::XPropertySet > xPropSet( rChartDoc->getLegend(), uno::UNO_QUERY );
1440
0
            if( xPropSet.is())
1441
0
                aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
1442
0
        }
1443
1444
0
        if( bExportContent )
1445
0
        {
1446
0
            Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY );
1447
0
            if( xProp.is())
1448
0
            {
1449
                // export legend anchor position
1450
0
                try
1451
0
                {
1452
0
                    Any aAny( xProp->getPropertyValue(u"Alignment"_ustr));
1453
0
                    if( SchXMLEnumConverter::getLegendPositionConverter().exportXML( msString, aAny, mrExport.GetMM100UnitConverter() ) )
1454
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LEGEND_POSITION, msString );
1455
0
                }
1456
0
                catch( const beans::UnknownPropertyException & )
1457
0
                {
1458
0
                    SAL_WARN("xmloff.chart", "Property Align not found in ChartLegend" );
1459
0
                }
1460
1461
                // export legend overlay
1462
0
                try
1463
0
                {
1464
0
                    if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED)
1465
0
                    {
1466
0
                        Any aAny( xProp->getPropertyValue(u"Overlay"_ustr));
1467
0
                        if(aAny.get<bool>())
1468
0
                            mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_OVERLAY, OUString::boolean(true));
1469
0
                    }
1470
0
                }
1471
0
                catch( const beans::UnknownPropertyException & )
1472
0
                {
1473
0
                    SAL_WARN("xmloff.chart", "Property Overlay not found in ChartLegend" );
1474
0
                }
1475
1476
                // export absolute legend position
1477
0
                Reference< drawing::XShape > xLegendShape( xProp, uno::UNO_QUERY );
1478
0
                addPosition( xLegendShape );
1479
1480
                // export legend size
1481
0
                if (xLegendShape.is() && nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
1482
0
                {
1483
0
                    try
1484
0
                    {
1485
0
                        chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH;
1486
0
                        OUString aExpansionString;
1487
0
                        Any aAny( xProp->getPropertyValue(u"Expansion"_ustr));
1488
0
                        bool bHasExpansion = (aAny >>= nLegendExpansion);
1489
0
                        if( bHasExpansion && SchXMLEnumConverter::getLegendExpansionConverter().exportXML( aExpansionString, aAny, mrExport.GetMM100UnitConverter() ) )
1490
0
                        {
1491
0
                            mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION, aExpansionString );
1492
0
                            if( nLegendExpansion == chart::ChartLegendExpansion_CUSTOM)
1493
0
                            {
1494
0
                                awt::Size aSize( xLegendShape->getSize() );
1495
                                // tdf#131966: chart legend attributes width and height shouldn't be exported to ODF 1.2 (strict)
1496
0
                                if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_013)
1497
0
                                {   // ODF 1.3 OFFICE-3883
1498
0
                                    addSize( aSize, false );
1499
0
                                }
1500
0
                                else if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED)
1501
0
                                {
1502
0
                                    addSize( aSize, true );
1503
0
                                }
1504
0
                                OUStringBuffer aAspectRatioString;
1505
0
                                ::sax::Converter::convertDouble(
1506
0
                                    aAspectRatioString,
1507
0
                                    (aSize.Height == 0
1508
0
                                     ? 1.0
1509
0
                                     : double(aSize.Width)/double(aSize.Height)));
1510
0
                                mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO, aAspectRatioString.makeStringAndClear() );
1511
0
                            }
1512
0
                        }
1513
0
                    }
1514
0
                    catch( const beans::UnknownPropertyException & )
1515
0
                    {
1516
0
                        SAL_WARN("xmloff.chart", "Property Expansion not found in ChartLegend" );
1517
0
                    }
1518
0
                }
1519
0
            }
1520
1521
            // write style name
1522
0
            AddAutoStyleAttribute( aPropertyStates );
1523
1524
            // element
1525
0
            SvXMLElementExport aLegend( mrExport, XML_NAMESPACE_CHART, XML_LEGEND, true, true );
1526
0
        }
1527
0
        else    // autostyles
1528
0
        {
1529
0
            CollectAutoStyle( std::move(aPropertyStates) );
1530
0
        }
1531
        // remove property states for autostyles
1532
0
        aPropertyStates.clear();
1533
0
    }
1534
1535
    // Export data table element and properties
1536
0
    if (xNewDiagram.is() && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED)
1537
0
    {
1538
0
        auto xDataTable = xNewDiagram->getDataTable();
1539
1540
0
        if (xDataTable.is())
1541
0
        {
1542
            // get property states for autostyles
1543
0
            if (mxExpPropMapper.is())
1544
0
            {
1545
0
                uno::Reference<beans::XPropertySet> xPropSet(xDataTable, uno::UNO_QUERY);
1546
0
                if (xPropSet.is())
1547
0
                    aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
1548
0
            }
1549
1550
0
            if (bExportContent)
1551
0
            {
1552
                // add style name attribute
1553
0
                AddAutoStyleAttribute(aPropertyStates);
1554
0
                SvXMLElementExport aDataTableElement(mrExport, XML_NAMESPACE_LO_EXT, XML_DATA_TABLE, true, true);
1555
0
            }
1556
0
            else
1557
0
            {
1558
0
                CollectAutoStyle(std::move(aPropertyStates));
1559
0
            }
1560
0
        }
1561
1562
        // remove property states for autostyles
1563
0
        aPropertyStates.clear();
1564
0
    }
1565
1566
    // plot-area element
1567
0
    if( xDiagram.is())
1568
0
        exportPlotArea( xDiagram, xNewDiagram, aPageSize, bExportContent, bIncludeTable );
1569
1570
    // export additional shapes
1571
0
    if( xDocPropSet.is() )
1572
0
    {
1573
0
        if( bExportContent )
1574
0
        {
1575
0
            if( mxAdditionalShapes.is())
1576
0
            {
1577
                // can't call exportShapes with all shapes because the
1578
                // initialisation happened with the complete draw page and not
1579
                // the XShapes object used here. Thus the shapes have to be
1580
                // exported one by one
1581
0
                rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport();
1582
0
                Reference< drawing::XShape > xShape;
1583
0
                const sal_Int32 nShapeCount( mxAdditionalShapes->getCount());
1584
0
                for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ )
1585
0
                {
1586
0
                    mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape;
1587
0
                    SAL_WARN_IF( !xShape.is(), "xmloff.chart",  "Shape without an XShape?" );
1588
0
                    if( ! xShape.is())
1589
0
                        continue;
1590
1591
0
                    rShapeExport->exportShape( xShape );
1592
0
                }
1593
                // this would be the easier way if it worked:
1594
                //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes );
1595
0
            }
1596
0
        }
1597
0
        else
1598
0
        {
1599
            // get a sequence of non-chart shapes (inserted via clipboard)
1600
0
            try
1601
0
            {
1602
0
                Any aShapesAny = xDocPropSet->getPropertyValue(u"AdditionalShapes"_ustr);
1603
0
                aShapesAny >>= mxAdditionalShapes;
1604
0
            }
1605
0
            catch( const uno::Exception & )
1606
0
            {
1607
0
                TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found" );
1608
0
            }
1609
1610
0
            if( mxAdditionalShapes.is())
1611
0
            {
1612
                // seek shapes has to be called for the whole page because in
1613
                // the shape export the vector of shapes is accessed via the
1614
                // ZOrder which might be (actually is) larger than the number of
1615
                // shapes in mxAdditionalShapes
1616
0
                Reference< drawing::XDrawPageSupplier > xSupplier( rChartDoc, uno::UNO_QUERY );
1617
0
                SAL_WARN_IF( !xSupplier.is(), "xmloff.chart", "Cannot retrieve draw page to initialize shape export" );
1618
0
                if( xSupplier.is() )
1619
0
                {
1620
0
                    Reference< drawing::XShapes > xDrawPage = xSupplier->getDrawPage();
1621
0
                    SAL_WARN_IF( !xDrawPage.is(), "xmloff.chart", "Invalid draw page for initializing shape export" );
1622
0
                    if( xDrawPage.is())
1623
0
                        mrExport.GetShapeExport()->seekShapes( xDrawPage );
1624
0
                }
1625
1626
                // can't call collectShapesAutoStyles with all shapes because
1627
                // the initialisation happened with the complete draw page and
1628
                // not the XShapes object used here. Thus the shapes have to be
1629
                // exported one by one
1630
0
                rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport();
1631
0
                Reference< drawing::XShape > xShape;
1632
0
                const sal_Int32 nShapeCount( mxAdditionalShapes->getCount());
1633
0
                for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ )
1634
0
                {
1635
0
                    mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape;
1636
0
                    SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" );
1637
0
                    if( ! xShape.is())
1638
0
                        continue;
1639
1640
0
                    rShapeExport->collectShapeAutoStyles( xShape );
1641
0
                }
1642
0
            }
1643
0
        }
1644
0
    }
1645
1646
    // table element
1647
    // (is included as subelement of chart)
1648
0
    if( bExportContent )
1649
0
    {
1650
        // #85929# always export table, otherwise clipboard may lose data
1651
0
        exportTable();
1652
0
    }
1653
0
}
1654
1655
static void lcl_exportComplexLabel( const Sequence< uno::Any >& rComplexLabel, SvXMLExport& rExport )
1656
0
{
1657
0
    sal_Int32 nLength = rComplexLabel.getLength();
1658
0
    if( nLength<=1 )
1659
0
        return;
1660
0
    SvXMLElementExport aTextList( rExport, XML_NAMESPACE_TEXT, XML_LIST, true, true );
1661
0
    for(const auto& rElem : rComplexLabel)
1662
0
    {
1663
0
        SvXMLElementExport aListItem( rExport, XML_NAMESPACE_TEXT, XML_LIST_ITEM, true, true );
1664
0
        OUString aString;
1665
0
        if( !(rElem >>= aString) )
1666
0
        {
1667
0
            double aNum;
1668
0
            if (rElem >>= aNum)
1669
0
            {
1670
0
                aString = OUString::number(aNum);
1671
0
            }
1672
0
        }
1673
0
        SchXMLTools::exportText( rExport, aString, false /*bConvertTabsLFs*/ );
1674
0
    }
1675
0
}
1676
1677
void SchXMLExportHelper_Impl::exportTable()
1678
0
{
1679
    // table element
1680
0
    mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, gsTableName );
1681
1682
0
    try
1683
0
    {
1684
0
        bool bProtected = false;
1685
0
        Reference< beans::XPropertySet > xProps( mrExport.GetModel(), uno::UNO_QUERY );
1686
0
        if ( xProps &&
1687
0
             ( xProps->getPropertyValue(u"DisableDataTableDialog"_ustr) >>= bProtected ) &&
1688
0
             bProtected )
1689
0
        {
1690
0
            mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE );
1691
0
        }
1692
0
    }
1693
0
    catch ( const uno::Exception& )
1694
0
    {
1695
0
    }
1696
1697
0
    SvXMLElementExport aTable( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true );
1698
1699
0
    bool bHasOwnData = false;
1700
0
    Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
1701
0
    Reference< chart2::data::XRangeXMLConversion > xRangeConversion;
1702
0
    if( xNewDoc.is())
1703
0
    {
1704
0
        bHasOwnData = xNewDoc->hasInternalDataProvider();
1705
0
        xRangeConversion.set( xNewDoc->getDataProvider(), uno::UNO_QUERY );
1706
0
    }
1707
1708
0
    Reference< chart2::XAnyDescriptionAccess > xAnyDescriptionAccess;
1709
0
    {
1710
0
        Reference< chart::XChartDocument > xChartDoc( mrExport.GetModel(), uno::UNO_QUERY );
1711
0
        if( xChartDoc.is() )
1712
0
            xAnyDescriptionAccess.set( xChartDoc->getData(), uno::UNO_QUERY );
1713
0
    }
1714
1715
0
    if( bHasOwnData )
1716
0
        lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport );
1717
0
    lcl_TableData aData( lcl_getDataForLocalTable( m_aDataSequencesToExport
1718
0
                                , xAnyDescriptionAccess, maCategoriesRange
1719
0
                                , mbRowSourceColumns, xRangeConversion ));
1720
1721
0
    tStringVector::const_iterator aDataRangeIter( aData.aDataRangeRepresentations.begin());
1722
0
    const tStringVector::const_iterator aDataRangeEndIter( aData.aDataRangeRepresentations.end());
1723
1724
0
    tStringVector::const_iterator aRowDescriptions_RangeIter( aData.aRowDescriptions_Ranges.begin());
1725
0
    const tStringVector::const_iterator aRowDescriptions_RangeEnd( aData.aRowDescriptions_Ranges.end());
1726
1727
    // declare columns
1728
0
    {
1729
0
        SvXMLElementExport aHeaderColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true, true );
1730
0
        SvXMLElementExport aHeaderColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1731
0
    }
1732
0
    {
1733
0
        SvXMLElementExport aColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, true, true );
1734
1735
0
        sal_Int32 nNextIndex = 0;
1736
0
        for(sal_Int32 nHiddenIndex : aData.aHiddenColumns)
1737
0
        {
1738
            //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste )
1739
0
            if( nHiddenIndex > nNextIndex )
1740
0
            {
1741
0
                sal_Int64 nRepeat = static_cast< sal_Int64 >( nHiddenIndex - nNextIndex );
1742
0
                if(nRepeat>1)
1743
0
                    mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
1744
0
                                   OUString::number( nRepeat ));
1745
0
                SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1746
0
            }
1747
0
            mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_VISIBILITY, GetXMLToken( XML_COLLAPSE ) );
1748
0
            SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1749
0
            nNextIndex = nHiddenIndex+1;
1750
0
        }
1751
1752
0
        sal_Int32 nEndIndex = aData.aColumnDescriptions.size()-1;
1753
0
        if( nEndIndex >= nNextIndex )
1754
0
        {
1755
0
            sal_Int64 nRepeat = static_cast< sal_Int64 >( nEndIndex - nNextIndex + 1 );
1756
0
            if(nRepeat>1)
1757
0
                mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
1758
0
                               OUString::number( nRepeat ));
1759
0
            SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1760
0
        }
1761
0
    }
1762
1763
    // export rows with content
1764
    //export header row
1765
0
    {
1766
0
        SvXMLElementExport aHeaderRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true, true );
1767
0
        SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true );
1768
1769
        //first one empty cell for the row descriptions
1770
0
        {
1771
0
            SvXMLElementExport aEmptyCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1772
0
            SvXMLElementExport aEmptyParagraph( mrExport, XML_NAMESPACE_TEXT, XML_P, true, true );
1773
0
        }
1774
1775
        //export column descriptions
1776
0
        tStringVector::const_iterator aColumnDescriptions_RangeIter( aData.aColumnDescriptions_Ranges.begin());
1777
0
        const tStringVector::const_iterator aColumnDescriptions_RangeEnd( aData.aColumnDescriptions_Ranges.end());
1778
0
        const Sequence< Sequence< uno::Any > >& rComplexColumnDescriptions = aData.aComplexColumnDescriptions;
1779
0
        sal_Int32 nComplexCount = rComplexColumnDescriptions.getLength();
1780
0
        sal_Int32 nC = 0;
1781
0
        for( const auto& rDesc : aData.aColumnDescriptions )
1782
0
        {
1783
0
            bool bExportString = true;
1784
0
            if( nC < nComplexCount )
1785
0
            {
1786
0
                const Sequence< uno::Any >& rComplexLabel = rComplexColumnDescriptions[nC];
1787
0
                if( rComplexLabel.hasElements() )
1788
0
                {
1789
0
                    double fValue=0.0;
1790
0
                    if( rComplexLabel[0] >>=fValue )
1791
0
                    {
1792
0
                        bExportString = false;
1793
1794
0
                        ::sax::Converter::convertDouble(
1795
0
                                msStringBuffer, fValue);
1796
0
                        msString = msStringBuffer.makeStringAndClear();
1797
0
                        mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT );
1798
0
                        mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString );
1799
0
                    }
1800
0
                }
1801
0
            }
1802
0
            if( bExportString )
1803
0
            {
1804
0
                mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING );
1805
0
            }
1806
1807
0
            SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1808
0
            exportText( rDesc );
1809
0
            if( nC < nComplexCount )
1810
0
                lcl_exportComplexLabel( rComplexColumnDescriptions[nC], mrExport );
1811
0
            if( !bHasOwnData && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd )
1812
0
            {
1813
                // remind the original range to allow a correct re-association when copying via clipboard
1814
0
                if (!(*aColumnDescriptions_RangeIter).isEmpty())
1815
0
                    SchXMLTools::exportRangeToSomewhere( mrExport, *aColumnDescriptions_RangeIter );
1816
0
                ++aColumnDescriptions_RangeIter;
1817
0
            }
1818
1819
0
            nC++;
1820
0
        }
1821
0
        SAL_WARN_IF( !bHasOwnData && (aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" );
1822
0
    } // closing row and header-rows elements
1823
1824
    // export value rows
1825
0
    {
1826
0
        SvXMLElementExport aRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROWS, true, true );
1827
0
        tStringVector::const_iterator aRowDescriptionsIter( aData.aRowDescriptions.begin());
1828
0
        const Sequence< Sequence< uno::Any > >& rComplexRowDescriptions = aData.aComplexRowDescriptions;
1829
0
        sal_Int32 nComplexCount = rComplexRowDescriptions.getLength();
1830
0
        sal_Int32 nC = 0;
1831
1832
0
        for( const auto& rRow : aData.aDataInRows )
1833
0
        {
1834
0
            SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true );
1835
1836
            //export row descriptions
1837
0
            {
1838
0
                bool bExportString = true;
1839
0
                if( nC < nComplexCount )
1840
0
                {
1841
0
                    const Sequence< uno::Any >& rComplexLabel = rComplexRowDescriptions[nC];
1842
0
                    if( rComplexLabel.hasElements() )
1843
0
                    {
1844
0
                        double fValue=0.0;
1845
0
                        if( rComplexLabel[0] >>=fValue )
1846
0
                        {
1847
0
                            bExportString = false;
1848
1849
0
                            ::sax::Converter::convertDouble(msStringBuffer, fValue);
1850
0
                            msString = msStringBuffer.makeStringAndClear();
1851
0
                            mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT );
1852
0
                            mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString );
1853
0
                        }
1854
0
                    }
1855
0
                }
1856
0
                if( bExportString )
1857
0
                {
1858
0
                    mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING );
1859
0
                }
1860
1861
0
                SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1862
0
                if( aRowDescriptionsIter != aData.aRowDescriptions.end())
1863
0
                {
1864
0
                    exportText( *aRowDescriptionsIter );
1865
0
                    if( nC < nComplexCount )
1866
0
                        lcl_exportComplexLabel( rComplexRowDescriptions[nC], mrExport );
1867
0
                    if( !bHasOwnData && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd )
1868
0
                    {
1869
                        // remind the original range to allow a correct re-association when copying via clipboard
1870
0
                        SchXMLTools::exportRangeToSomewhere( mrExport, *aRowDescriptions_RangeIter );
1871
0
                        ++aRowDescriptions_RangeIter;
1872
0
                    }
1873
0
                    ++aRowDescriptionsIter;
1874
0
                }
1875
0
            }
1876
1877
            //export row values
1878
0
            for( t2DNumberContainer::value_type::const_iterator aColIt( rRow.begin());
1879
0
                 aColIt != rRow.end(); ++aColIt )
1880
0
            {
1881
0
                ::sax::Converter::convertDouble( msStringBuffer, *aColIt );
1882
0
                msString = msStringBuffer.makeStringAndClear();
1883
0
                mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT );
1884
0
                mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString );
1885
0
                SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1886
0
                exportText( msString ); // do not convert tabs and lfs
1887
0
                if( ( !bHasOwnData && aDataRangeIter != aDataRangeEndIter ) &&
1888
0
                    ( mbRowSourceColumns || (aColIt == rRow.begin()) ) )
1889
0
                {
1890
                    // remind the original range to allow a correct re-association when copying via clipboard
1891
0
                    if (!(*aDataRangeIter).isEmpty())
1892
0
                        SchXMLTools::exportRangeToSomewhere( mrExport, *aDataRangeIter );
1893
0
                    ++aDataRangeIter;
1894
0
                }
1895
0
            }
1896
1897
0
            ++nC;
1898
0
        }
1899
0
    }
1900
1901
    // if range iterator was used it should have reached its end
1902
0
    SAL_WARN_IF( !bHasOwnData && (aDataRangeIter != aDataRangeEndIter), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" );
1903
0
    SAL_WARN_IF( !bHasOwnData && (aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" );
1904
0
}
1905
1906
namespace
1907
{
1908
1909
Reference< chart2::XCoordinateSystem > lcl_getCooSys( const Reference< chart2::XDiagram > & xNewDiagram )
1910
0
{
1911
0
    Reference< chart2::XCoordinateSystem > xCooSys;
1912
0
    Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDiagram, uno::UNO_QUERY );
1913
0
    if(xCooSysCnt.is())
1914
0
    {
1915
0
        Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
1916
0
        if(aCooSysSeq.hasElements())
1917
0
            xCooSys = aCooSysSeq[0];
1918
0
    }
1919
0
    return xCooSys;
1920
0
}
1921
1922
Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& xCooSys,
1923
        enum XMLTokenEnum eDimension, bool bPrimary=true )
1924
0
{
1925
0
    Reference< chart2::XAxis > xNewAxis;
1926
0
    try
1927
0
    {
1928
0
        if( xCooSys.is() )
1929
0
        {
1930
0
            sal_Int32 nDimensionIndex=0;
1931
0
            switch( eDimension )
1932
0
            {
1933
0
            case XML_X:
1934
0
                nDimensionIndex=0;
1935
0
                break;
1936
0
            case XML_Y:
1937
0
                nDimensionIndex=1;
1938
0
                break;
1939
0
            case XML_Z:
1940
0
                nDimensionIndex=2;
1941
0
                break;
1942
0
            default:
1943
0
                break;
1944
0
            }
1945
1946
0
            xNewAxis = xCooSys->getAxisByDimension( nDimensionIndex, bPrimary ? 0 : 1 );
1947
0
        }
1948
0
    }
1949
0
    catch( const uno::Exception & )
1950
0
    {
1951
0
    }
1952
0
    return xNewAxis;
1953
0
}
1954
1955
}
1956
1957
void SchXMLExportHelper_Impl::exportPlotArea(
1958
    const Reference< chart::XDiagram >& xDiagram,
1959
    const Reference< chart2::XDiagram >& xNewDiagram,
1960
    const awt::Size & rPageSize,
1961
    bool bExportContent,
1962
    bool bIncludeTable )
1963
0
{
1964
0
    SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
1965
0
    if( ! xDiagram.is())
1966
0
        return;
1967
1968
    // variables for autostyles
1969
0
    Reference< beans::XPropertySet > xPropSet;
1970
0
    std::vector< XMLPropertyState > aPropertyStates;
1971
1972
0
    msStringBuffer.setLength( 0 );
1973
1974
    // plot-area element
1975
1976
0
    std::unique_ptr<SvXMLElementExport> xElPlotArea;
1977
    // get property states for autostyles
1978
0
    xPropSet.set( xDiagram, uno::UNO_QUERY );
1979
0
    if( xPropSet.is())
1980
0
    {
1981
0
        if( mxExpPropMapper.is())
1982
0
            aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
1983
0
    }
1984
0
    if( bExportContent )
1985
0
    {
1986
0
        rtl::Reference< XMLShapeExport > rShapeExport;
1987
1988
        // write style name
1989
0
        AddAutoStyleAttribute( aPropertyStates );
1990
1991
        // The attribute table:cell-range-address was removed from the standard in ODF 1.4.
1992
        // The associated attribute chart:data-source-has-labels is deprecated.
1993
0
        const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(mrExport.getSaneDefaultVersion());
1994
0
        if( !msChartAddress.isEmpty() && nCurrentODFVersion < SvtSaveOptions::ODFSVER_014)
1995
0
        {
1996
0
            if( !bIncludeTable )
1997
0
                mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, msChartAddress );
1998
1999
0
            Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY );
2000
0
            if( xDoc.is() )
2001
0
            {
2002
0
                Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY );
2003
0
                if( xDocProp.is())
2004
0
                {
2005
0
                    Any aAny;
2006
2007
0
                    try
2008
0
                    {
2009
0
                        bool bFirstCol = false, bFirstRow = false;
2010
2011
0
                        aAny = xDocProp->getPropertyValue( u"DataSourceLabelsInFirstColumn"_ustr );
2012
0
                        aAny >>= bFirstCol;
2013
0
                        aAny = xDocProp->getPropertyValue( u"DataSourceLabelsInFirstRow"_ustr );
2014
0
                        aAny >>= bFirstRow;
2015
2016
0
                        if( bFirstCol || bFirstRow )
2017
0
                        {
2018
0
                            mrExport.AddAttribute( XML_NAMESPACE_CHART,
2019
0
                                                   ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS ),
2020
0
                                                   ( bFirstCol
2021
0
                                                     ? ( bFirstRow
2022
0
                                                         ?  ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH )
2023
0
                                                         :  ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN ))
2024
0
                                                     : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW )));
2025
0
                        }
2026
0
                    }
2027
0
                    catch( const beans::UnknownPropertyException & )
2028
0
                    {
2029
0
                        SAL_WARN("xmloff.chart", "Properties missing" );
2030
0
                    }
2031
0
                }
2032
0
            }
2033
0
        }
2034
2035
        // attributes
2036
0
        if( xDiagram.is())
2037
0
        {
2038
0
            addPosition( xDiagram );
2039
0
            addSize( xDiagram );
2040
0
        }
2041
2042
0
        bool bIs3DChart = false;
2043
2044
0
        if( xPropSet.is())
2045
0
        {
2046
0
            Any aAny;
2047
2048
            // 3d attributes
2049
0
            try
2050
0
            {
2051
0
                aAny = xPropSet->getPropertyValue(u"Dim3D"_ustr);
2052
0
                aAny >>= bIs3DChart;
2053
2054
0
                if( bIs3DChart )
2055
0
                {
2056
0
                    rShapeExport = mrExport.GetShapeExport();
2057
0
                    if( rShapeExport.is())
2058
0
                        rShapeExport->export3DSceneAttributes( xPropSet );
2059
0
                }
2060
0
            }
2061
0
            catch( const uno::Exception & )
2062
0
            {
2063
0
                TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught");
2064
0
            }
2065
0
        }
2066
2067
        // plot-area element
2068
0
        xElPlotArea.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_PLOT_AREA, true, true ));
2069
2070
        //inner position rectangle element
2071
0
        exportCoordinateRegion( xDiagram );
2072
2073
        // light sources (inside plot area element)
2074
0
        if( bIs3DChart &&
2075
0
            rShapeExport.is())
2076
0
            rShapeExport->export3DLamps( xPropSet );
2077
0
    }
2078
0
    else    // autostyles
2079
0
    {
2080
0
        CollectAutoStyle( std::move(aPropertyStates) );
2081
0
    }
2082
    // remove property states for autostyles
2083
0
    aPropertyStates.clear();
2084
2085
    // axis elements
2086
0
    exportAxes( xDiagram, xNewDiagram, bExportContent );
2087
2088
    // series elements
2089
0
    Reference< chart2::XAxis > xSecondYAxis = lcl_getAxis( lcl_getCooSys( xNewDiagram ), XML_Y, false );
2090
0
    exportSeries( xNewDiagram, rPageSize, bExportContent, xSecondYAxis.is() );
2091
2092
    // stock-chart elements
2093
0
    OUString sChartType ( xDiagram->getDiagramType());
2094
0
    if( sChartType == "com.sun.star.chart.StockDiagram" )
2095
0
    {
2096
0
        Reference< chart::XStatisticDisplay > xStockPropProvider( xDiagram, uno::UNO_QUERY );
2097
0
        if( xStockPropProvider.is())
2098
0
        {
2099
            // stock-gain-marker
2100
0
            Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getUpBar();
2101
0
            if( xStockPropSet.is())
2102
0
            {
2103
0
                aPropertyStates.clear();
2104
0
                aPropertyStates = mxExpPropMapper->Filter(mrExport, xStockPropSet);
2105
2106
0
                if( !aPropertyStates.empty() )
2107
0
                {
2108
0
                    if( bExportContent )
2109
0
                    {
2110
0
                        AddAutoStyleAttribute( aPropertyStates );
2111
2112
0
                        SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_GAIN_MARKER, true, true );
2113
0
                    }
2114
0
                    else
2115
0
                    {
2116
0
                        CollectAutoStyle( std::move(aPropertyStates) );
2117
0
                    }
2118
0
                }
2119
0
            }
2120
2121
            // stock-loss-marker
2122
0
            xStockPropSet = xStockPropProvider->getDownBar();
2123
0
            if( xStockPropSet.is())
2124
0
            {
2125
0
                aPropertyStates.clear();
2126
0
                aPropertyStates = mxExpPropMapper->Filter(mrExport, xStockPropSet);
2127
2128
0
                if( !aPropertyStates.empty() )
2129
0
                {
2130
0
                    if( bExportContent )
2131
0
                    {
2132
0
                        AddAutoStyleAttribute( aPropertyStates );
2133
2134
0
                        SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_LOSS_MARKER, true, true );
2135
0
                    }
2136
0
                    else
2137
0
                    {
2138
0
                        CollectAutoStyle( std::move(aPropertyStates) );
2139
0
                    }
2140
0
                }
2141
0
            }
2142
2143
            // stock-range-line
2144
0
            xStockPropSet = xStockPropProvider->getMinMaxLine();
2145
0
            if( xStockPropSet.is())
2146
0
            {
2147
0
                aPropertyStates.clear();
2148
0
                aPropertyStates = mxExpPropMapper->Filter(mrExport, xStockPropSet);
2149
2150
0
                if( !aPropertyStates.empty() )
2151
0
                {
2152
0
                    if( bExportContent )
2153
0
                    {
2154
0
                        AddAutoStyleAttribute( aPropertyStates );
2155
2156
0
                        SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_RANGE_LINE, true, true );
2157
0
                    }
2158
0
                    else
2159
0
                    {
2160
0
                        CollectAutoStyle( std::move(aPropertyStates) );
2161
0
                    }
2162
0
                }
2163
0
            }
2164
0
        }
2165
0
    }
2166
2167
    // wall and floor element
2168
0
    Reference< chart::X3DDisplay > xWallFloorSupplier( xDiagram, uno::UNO_QUERY );
2169
0
    if( !(mxExpPropMapper.is() &&
2170
0
        xWallFloorSupplier.is()))
2171
0
        return;
2172
2173
    // remove property states for autostyles
2174
0
    aPropertyStates.clear();
2175
2176
0
    Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall();
2177
0
    if( xWallPropSet.is())
2178
0
    {
2179
0
        aPropertyStates = mxExpPropMapper->Filter(mrExport, xWallPropSet);
2180
2181
0
        if( !aPropertyStates.empty() )
2182
0
        {
2183
            // write element
2184
0
            if( bExportContent )
2185
0
            {
2186
                // add style name attribute
2187
0
                AddAutoStyleAttribute( aPropertyStates );
2188
2189
0
                SvXMLElementExport aWall( mrExport, XML_NAMESPACE_CHART, XML_WALL, true, true );
2190
0
            }
2191
0
            else    // autostyles
2192
0
            {
2193
0
                CollectAutoStyle( std::move(aPropertyStates) );
2194
0
            }
2195
0
        }
2196
0
    }
2197
2198
    // floor element
2199
    // remove property states for autostyles
2200
0
    aPropertyStates.clear();
2201
2202
0
    Reference< beans::XPropertySet > xFloorPropSet = xWallFloorSupplier->getFloor();
2203
0
    if( !xFloorPropSet.is())
2204
0
        return;
2205
2206
0
    aPropertyStates = mxExpPropMapper->Filter(mrExport, xFloorPropSet);
2207
2208
0
    if( aPropertyStates.empty() )
2209
0
        return;
2210
2211
    // write element
2212
0
    if( bExportContent )
2213
0
    {
2214
        // add style name attribute
2215
0
        AddAutoStyleAttribute( aPropertyStates );
2216
2217
0
        SvXMLElementExport aFloor( mrExport, XML_NAMESPACE_CHART, XML_FLOOR, true, true );
2218
0
    }
2219
0
    else    // autostyles
2220
0
    {
2221
0
        CollectAutoStyle( std::move(aPropertyStates) );
2222
0
    }
2223
0
}
2224
2225
void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference< chart::XDiagram >& xDiagram )
2226
0
{
2227
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
2228
0
        mrExport.getSaneDefaultVersion());
2229
0
    if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
2230
0
        return;
2231
2232
0
    Reference< chart::XDiagramPositioning > xDiaPos( xDiagram, uno::UNO_QUERY );
2233
0
    SAL_WARN_IF( !xDiaPos.is(), "xmloff.chart", "Invalid xDiaPos as parameter" );
2234
0
    if( !xDiaPos.is() )
2235
0
        return;
2236
2237
0
    awt::Rectangle aRect( xDiaPos->calculateDiagramPositionExcludingAxes() );
2238
0
    addPosition( awt::Point(aRect.X,aRect.Y) );
2239
0
    addSize( awt::Size(aRect.Width,aRect.Height) );
2240
2241
    // ODF 1.3 OFFICE-3928
2242
0
    SvXMLElementExport aCoordinateRegion( mrExport,
2243
0
        (SvtSaveOptions::ODFSVER_013 <= nCurrentODFVersion) ? XML_NAMESPACE_CHART : XML_NAMESPACE_CHART_EXT,
2244
0
        XML_COORDINATE_REGION, true, true );
2245
0
}
2246
2247
namespace
2248
{
2249
    XMLTokenEnum lcl_getTimeUnitToken( sal_Int32 nTimeUnit )
2250
0
    {
2251
0
        XMLTokenEnum eToken = XML_DAYS;
2252
0
        switch( nTimeUnit )
2253
0
        {
2254
0
        case css::chart::TimeUnit::YEAR:
2255
0
            eToken = XML_YEARS;
2256
0
            break;
2257
0
        case css::chart::TimeUnit::MONTH:
2258
0
            eToken = XML_MONTHS;
2259
0
            break;
2260
0
        default://days
2261
0
            break;
2262
0
        }
2263
0
        return eToken;
2264
0
    }
2265
}
2266
2267
void SchXMLExportHelper_Impl::exportDateScale( const Reference< beans::XPropertySet >& rAxisProps )
2268
0
{
2269
0
    if( !rAxisProps.is() )
2270
0
        return;
2271
2272
0
    chart::TimeIncrement aIncrement;
2273
0
    if( !(rAxisProps->getPropertyValue(u"TimeIncrement"_ustr) >>= aIncrement) )
2274
0
        return;
2275
2276
0
    sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY;
2277
0
    if( aIncrement.TimeResolution >>= nTimeResolution )
2278
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, lcl_getTimeUnitToken( nTimeResolution ) );
2279
2280
0
    chart::TimeInterval aInterval;
2281
0
    if( aIncrement.MajorTimeInterval >>= aInterval )
2282
0
    {
2283
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, OUString::number(aInterval.Number) );
2284
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) );
2285
0
    }
2286
0
    if( aIncrement.MinorTimeInterval >>= aInterval )
2287
0
    {
2288
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, OUString::number(aInterval.Number) );
2289
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) );
2290
0
    }
2291
2292
0
    SvXMLElementExport aDateScale( mrExport, XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, true, true );//#i25706#todo: change namespace for next ODF version
2293
0
}
2294
2295
void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent )
2296
0
{
2297
0
    if( !rTitleProps.is() )
2298
0
        return;
2299
0
    std::vector<XMLPropertyState> aPropertyStates = mxExpPropMapper->Filter(mrExport, rTitleProps);
2300
0
    if( bExportContent )
2301
0
    {
2302
0
        Reference< drawing::XShape > xShape( rTitleProps, uno::UNO_QUERY );
2303
0
        if( xShape.is())
2304
0
            addPosition( xShape );
2305
2306
0
        AddAutoStyleAttribute( aPropertyStates );
2307
0
        SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true );
2308
2309
        // paragraph containing title
2310
0
        exportFormattedText( rTitleProps );
2311
0
    }
2312
0
    else
2313
0
    {
2314
0
        CollectAutoStyle( std::move(aPropertyStates) );
2315
0
        CollectAutoTextStyle( rTitleProps );
2316
0
    }
2317
0
    aPropertyStates.clear();
2318
0
}
2319
2320
void SchXMLExportHelper_Impl::exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent )
2321
0
{
2322
0
    if( !rGridProperties.is() )
2323
0
        return;
2324
0
    std::vector<XMLPropertyState> aPropertyStates = mxExpPropMapper->Filter(mrExport, rGridProperties);
2325
0
    if( bExportContent )
2326
0
    {
2327
0
        AddAutoStyleAttribute( aPropertyStates );
2328
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, bMajor ? XML_MAJOR : XML_MINOR );
2329
0
        SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, true, true );
2330
0
    }
2331
0
    else
2332
0
    {
2333
0
        CollectAutoStyle( std::move(aPropertyStates) );
2334
0
    }
2335
0
    aPropertyStates.clear();
2336
0
}
2337
2338
namespace
2339
{
2340
2341
//returns true if a date scale needs to be exported
2342
bool lcl_exportAxisType( const Reference< chart2::XAxis >& rChart2Axis, SvXMLExport& rExport)
2343
0
{
2344
0
    bool bExportDateScale = false;
2345
0
    if( !rChart2Axis.is() )
2346
0
        return bExportDateScale;
2347
2348
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
2349
0
        rExport.getSaneDefaultVersion());
2350
0
    if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) //do not export to ODF 1.3 or older
2351
0
        return bExportDateScale;
2352
2353
0
    chart2::ScaleData aScale( rChart2Axis->getScaleData() );
2354
    //#i25706#todo: change namespace for next ODF version
2355
0
    sal_uInt16 nNameSpace = XML_NAMESPACE_CHART_EXT;
2356
2357
0
    switch(aScale.AxisType)
2358
0
    {
2359
0
    case chart2::AxisType::CATEGORY:
2360
0
        if( aScale.AutoDateAxis )
2361
0
        {
2362
0
            rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO );
2363
0
            bExportDateScale = true;
2364
0
        }
2365
0
        else
2366
0
            rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_TEXT );
2367
0
        break;
2368
0
    case chart2::AxisType::DATE:
2369
0
        rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_DATE );
2370
0
        bExportDateScale = true;
2371
0
        break;
2372
0
    default: //AUTOMATIC
2373
0
        rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO );
2374
0
        break;
2375
0
    }
2376
2377
0
    return bExportDateScale;
2378
0
}
2379
2380
void disableLinkedNumberFormat(
2381
    std::vector<XMLPropertyState>& rPropStates, const rtl::Reference<XMLPropertySetMapper>& rMapper )
2382
0
{
2383
0
    for (XMLPropertyState & rState : rPropStates)
2384
0
    {
2385
0
        if (rState.mnIndex < 0 || rMapper->GetEntryCount() <= rState.mnIndex)
2386
0
            continue;
2387
2388
0
        OUString aXMLName = rMapper->GetEntryXMLName(rState.mnIndex);
2389
2390
0
        if (aXMLName != "link-data-style-to-source")
2391
0
            continue;
2392
2393
        // Entry found.  Set the value to false and bail out.
2394
0
        rState.maValue <<= false;
2395
0
        return;
2396
0
    }
2397
2398
    // Entry not found.  Insert a new entry for this.
2399
0
    sal_Int32 nIndex = rMapper->GetEntryIndex(XML_NAMESPACE_CHART, u"link-data-style-to-source", 0);
2400
0
    XMLPropertyState aState(nIndex);
2401
0
    aState.maValue <<= false;
2402
0
    rPropStates.push_back(aState);
2403
0
}
2404
2405
}
2406
2407
void SchXMLExportHelper_Impl::exportAxis(
2408
    enum XMLTokenEnum eDimension,
2409
    enum XMLTokenEnum eAxisName,
2410
    const Reference< beans::XPropertySet >& rAxisProps,
2411
    const Reference< chart2::XAxis >& rChart2Axis,
2412
    const OUString& rCategoriesRange,
2413
    bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid,
2414
    bool bExportContent, std::u16string_view sChartType )
2415
0
{
2416
0
    std::vector< XMLPropertyState > aPropertyStates;
2417
0
    std::unique_ptr<SvXMLElementExport> pAxis;
2418
2419
    // get property states for autostyles
2420
0
    if( rAxisProps.is() && mxExpPropMapper.is() )
2421
0
    {
2422
0
        const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
2423
0
            mrExport.getSaneDefaultVersion());
2424
0
        if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED
2425
0
            && eDimension == XML_X)
2426
0
        {
2427
0
            chart2::ScaleData aScaleData(rChart2Axis->getScaleData());
2428
0
            bool bShiftedCatPos = aScaleData.ShiftedCategoryPosition;
2429
0
            if (sChartType == u"com.sun.star.chart.BarDiagram" || sChartType == u"com.sun.star.chart.StockDiagram")
2430
0
            {
2431
0
                if (!bShiftedCatPos)
2432
0
                    rAxisProps->setPropertyValue(u"MajorOrigin"_ustr, uno::Any(0.0));
2433
0
            }
2434
0
            else if (bShiftedCatPos)
2435
0
                rAxisProps->setPropertyValue(u"MajorOrigin"_ustr, uno::Any(0.5));
2436
0
        }
2437
2438
0
        lcl_exportNumberFormat( u"NumberFormat"_ustr, rAxisProps, mrExport );
2439
0
        aPropertyStates = mxExpPropMapper->Filter(mrExport, rAxisProps);
2440
2441
0
        if (!maDestShellID.isEmpty() && (!maSrcShellID.isEmpty() || maSrcShellID != maDestShellID))
2442
0
        {
2443
            // Disable link to source number format property when pasting to
2444
            // a different doc shell.  These shell ID's should be both empty
2445
            // during real ODF export.
2446
0
            disableLinkedNumberFormat(aPropertyStates, mxExpPropMapper->getPropertySetMapper());
2447
0
        }
2448
0
    }
2449
2450
0
    bool bExportDateScale = false;
2451
0
    if( bExportContent )
2452
0
    {
2453
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, eDimension );
2454
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, eAxisName );
2455
0
        AddAutoStyleAttribute( aPropertyStates ); // write style name
2456
0
        if( !rCategoriesRange.isEmpty() )
2457
0
            bExportDateScale = lcl_exportAxisType( rChart2Axis, mrExport );
2458
2459
        // open axis element
2460
0
        pAxis.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, true, true ));
2461
0
    }
2462
0
    else
2463
0
    {
2464
0
        CollectAutoStyle( std::move(aPropertyStates) );
2465
0
    }
2466
0
    aPropertyStates.clear();
2467
2468
    //date scale
2469
0
    if( bExportDateScale )
2470
0
        exportDateScale( rAxisProps );
2471
2472
0
    Reference< beans::XPropertySet > xTitleProps;
2473
0
    Reference< beans::XPropertySet > xMajorGridProps;
2474
0
    Reference< beans::XPropertySet > xMinorGridProps;
2475
0
    Reference< chart::XAxis > xAxis( rAxisProps, uno::UNO_QUERY );
2476
0
    if( xAxis.is() )
2477
0
    {
2478
0
        xTitleProps = bHasTitle ? xAxis->getAxisTitle() : nullptr;
2479
0
        xMajorGridProps = bHasMajorGrid ? xAxis->getMajorGrid() : nullptr;
2480
0
        xMinorGridProps = bHasMinorGrid ? xAxis->getMinorGrid() : nullptr;
2481
0
    }
2482
2483
    // axis-title
2484
0
    exportAxisTitle( xTitleProps , bExportContent );
2485
2486
    // categories if we have a categories chart
2487
0
    if( bExportContent && !rCategoriesRange.isEmpty() )
2488
0
    {
2489
0
        mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, rCategoriesRange );
2490
0
        SvXMLElementExport aCategories( mrExport, XML_NAMESPACE_CHART, XML_CATEGORIES, true, true );
2491
0
    }
2492
2493
    // grid
2494
0
    exportGrid( xMajorGridProps, true, bExportContent );
2495
0
    exportGrid( xMinorGridProps, false, bExportContent );
2496
0
}
2497
2498
void SchXMLExportHelper_Impl::exportAxes(
2499
    const Reference< chart::XDiagram > & xDiagram,
2500
    const Reference< chart2::XDiagram > & xNewDiagram,
2501
    bool bExportContent )
2502
0
{
2503
0
    SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
2504
0
    if( ! xDiagram.is())
2505
0
        return;
2506
2507
    // get some properties from document first
2508
0
    bool bHasXAxis = false,
2509
0
        bHasYAxis = false,
2510
0
        bHasZAxis = false,
2511
0
        bHasSecondaryXAxis = false,
2512
0
        bHasSecondaryYAxis = false;
2513
0
    bool bHasXAxisTitle = false,
2514
0
        bHasYAxisTitle = false,
2515
0
        bHasZAxisTitle = false,
2516
0
        bHasSecondaryXAxisTitle = false,
2517
0
        bHasSecondaryYAxisTitle = false;
2518
0
    bool bHasXAxisMajorGrid = false,
2519
0
        bHasXAxisMinorGrid = false,
2520
0
        bHasYAxisMajorGrid = false,
2521
0
        bHasYAxisMinorGrid = false,
2522
0
        bHasZAxisMajorGrid = false,
2523
0
        bHasZAxisMinorGrid = false;
2524
2525
    // get multiple properties using XMultiPropertySet
2526
0
    MultiPropertySetHandler aDiagramProperties (xDiagram);
2527
2528
0
    aDiagramProperties.Add (u"HasXAxis"_ustr, bHasXAxis);
2529
0
    aDiagramProperties.Add (u"HasYAxis"_ustr, bHasYAxis);
2530
0
    aDiagramProperties.Add (u"HasZAxis"_ustr, bHasZAxis);
2531
0
    aDiagramProperties.Add (u"HasSecondaryXAxis"_ustr, bHasSecondaryXAxis);
2532
0
    aDiagramProperties.Add (u"HasSecondaryYAxis"_ustr, bHasSecondaryYAxis);
2533
2534
0
    aDiagramProperties.Add (u"HasXAxisTitle"_ustr, bHasXAxisTitle);
2535
0
    aDiagramProperties.Add (u"HasYAxisTitle"_ustr, bHasYAxisTitle);
2536
0
    aDiagramProperties.Add (u"HasZAxisTitle"_ustr, bHasZAxisTitle);
2537
0
    aDiagramProperties.Add (u"HasSecondaryXAxisTitle"_ustr, bHasSecondaryXAxisTitle);
2538
0
    aDiagramProperties.Add (u"HasSecondaryYAxisTitle"_ustr, bHasSecondaryYAxisTitle);
2539
2540
0
    aDiagramProperties.Add (u"HasXAxisGrid"_ustr, bHasXAxisMajorGrid);
2541
0
    aDiagramProperties.Add (u"HasYAxisGrid"_ustr, bHasYAxisMajorGrid);
2542
0
    aDiagramProperties.Add (u"HasZAxisGrid"_ustr, bHasZAxisMajorGrid);
2543
2544
0
    aDiagramProperties.Add (u"HasXAxisHelpGrid"_ustr, bHasXAxisMinorGrid);
2545
0
    aDiagramProperties.Add (u"HasYAxisHelpGrid"_ustr, bHasYAxisMinorGrid);
2546
0
    aDiagramProperties.Add (u"HasZAxisHelpGrid"_ustr, bHasZAxisMinorGrid);
2547
2548
0
    if ( ! aDiagramProperties.GetProperties ())
2549
0
    {
2550
0
        SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram");
2551
0
    }
2552
2553
0
    Reference< chart2::XCoordinateSystem > xCooSys( lcl_getCooSys(xNewDiagram) );
2554
2555
    // write an axis element also if the axis itself is not visible, but a grid or a title
2556
2557
0
    OUString aCategoriesRange;
2558
0
    Reference< chart::XAxisSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY );
2559
0
    OUString sChartType = xDiagram->getDiagramType();
2560
2561
    // x axis
2562
2563
0
    Reference< css::chart2::XAxis > xNewAxis = lcl_getAxis( xCooSys, XML_X );
2564
0
    if( xNewAxis.is() )
2565
0
    {
2566
0
        Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(0) : nullptr, uno::UNO_QUERY );
2567
0
        if( mbHasCategoryLabels && bExportContent )
2568
0
        {
2569
0
            Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) );
2570
0
            if( xCategories.is() )
2571
0
            {
2572
0
                Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() );
2573
0
                if( xValues.is() )
2574
0
                {
2575
0
                    Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2576
0
                    maCategoriesRange = xValues->getSourceRangeRepresentation();
2577
0
                    aCategoriesRange = lcl_ConvertRange( maCategoriesRange, xNewDoc );
2578
0
                }
2579
0
            }
2580
0
        }
2581
0
        exportAxis( XML_X, XML_PRIMARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasXAxisTitle, bHasXAxisMajorGrid, bHasXAxisMinorGrid, bExportContent, sChartType );
2582
0
        aCategoriesRange.clear();
2583
0
    }
2584
2585
    // secondary x axis
2586
2587
0
    xNewAxis = lcl_getAxis( xCooSys, XML_X, false );
2588
0
    if( xNewAxis.is() )
2589
0
    {
2590
0
        Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY );
2591
0
        exportAxis( XML_X, XML_SECONDARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryXAxisTitle, false, false, bExportContent, sChartType );
2592
0
    }
2593
2594
    // y axis
2595
2596
0
    xNewAxis = lcl_getAxis( xCooSys, XML_Y );
2597
0
    if( xNewAxis.is() )
2598
0
    {
2599
0
        Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(1) : nullptr, uno::UNO_QUERY );
2600
0
        exportAxis( XML_Y, XML_PRIMARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasYAxisTitle, bHasYAxisMajorGrid, bHasYAxisMinorGrid, bExportContent, sChartType );
2601
0
    }
2602
2603
    // secondary y axis
2604
2605
0
    xNewAxis = lcl_getAxis( xCooSys, XML_Y, false );
2606
0
    if( xNewAxis.is() )
2607
0
    {
2608
0
        Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY );
2609
0
        exportAxis( XML_Y, XML_SECONDARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryYAxisTitle, false, false, bExportContent, sChartType );
2610
0
    }
2611
2612
    // z axis
2613
2614
0
    xNewAxis = lcl_getAxis( xCooSys, XML_Z );
2615
0
    if( xNewAxis.is() )
2616
0
    {
2617
0
        Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(2) : nullptr, uno::UNO_QUERY );
2618
0
        exportAxis( XML_Z, XML_PRIMARY_Z, xAxisProps, xNewAxis, aCategoriesRange, bHasZAxisTitle, bHasZAxisMajorGrid, bHasZAxisMinorGrid, bExportContent, sChartType );
2619
0
    }
2620
0
}
2621
2622
namespace
2623
{
2624
    bool lcl_hasNoValuesButText( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
2625
0
    {
2626
0
        if( !xDataSequence.is() )
2627
0
            return false;//have no data
2628
2629
0
        Sequence< uno::Any > aData;
2630
0
        Reference< chart2::data::XNumericalDataSequence > xNumericalDataSequence( xDataSequence, uno::UNO_QUERY );
2631
0
        if( xNumericalDataSequence.is() )
2632
0
        {
2633
0
            const Sequence< double >  aDoubles( xNumericalDataSequence->getNumericalData() );
2634
0
            if (std::any_of(aDoubles.begin(), aDoubles.end(), [](double fDouble) { return !std::isnan( fDouble ); }))
2635
0
                return false;//have double value
2636
0
        }
2637
0
        else
2638
0
        {
2639
0
            aData = xDataSequence->getData();
2640
0
            double fDouble = 0.0;
2641
0
            bool bHaveDouble = std::any_of(std::cbegin(aData), std::cend(aData),
2642
0
                [&fDouble](const uno::Any& rData) { return (rData >>= fDouble) && !std::isnan( fDouble ); });
2643
0
            if (bHaveDouble)
2644
0
                return false;//have double value
2645
0
        }
2646
        //no values found
2647
2648
0
        Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY );
2649
0
        if( xTextualDataSequence.is() )
2650
0
        {
2651
0
            const uno::Sequence< OUString > aStrings( xTextualDataSequence->getTextualData() );
2652
0
            if (std::any_of(aStrings.begin(), aStrings.end(), [](const OUString& rString) { return !rString.isEmpty(); }))
2653
0
                return true;//have text
2654
0
        }
2655
0
        else
2656
0
        {
2657
0
            if( !aData.hasElements() )
2658
0
                aData = xDataSequence->getData();
2659
0
            OUString aString;
2660
0
            bool bHaveText = std::any_of(std::cbegin(aData), std::cend(aData),
2661
0
                [&aString](const uno::Any& rData) { return (rData >>= aString) && !aString.isEmpty(); });
2662
0
            if (bHaveText)
2663
0
                return true;//have text
2664
0
        }
2665
        //no doubles and no texts
2666
0
        return false;
2667
0
    }
2668
2669
// ODF has the line and fill properties in a <style:style> element, which is referenced by the
2670
// <chart:data-label> element. But LibreOffice has them as special label properties of the series
2671
// or point respectively. The following method generates ODF from internal API name.
2672
void lcl_createDataLabelProperties(
2673
    std::vector<XMLPropertyState>& rDataLabelPropertyStates,
2674
    const Reference<beans::XPropertySet>& xPropSet,
2675
    const rtl::Reference<XMLChartExportPropertyMapper>& xExpPropMapper)
2676
0
{
2677
0
    if (!xExpPropMapper.is() || !xPropSet.is())
2678
0
        return;
2679
2680
0
    const uno::Reference<beans::XPropertySetInfo> xInfo(xPropSet->getPropertySetInfo());
2681
0
    const uno::Reference<beans::XPropertyState> xPropState(xPropSet, uno::UNO_QUERY);
2682
0
    const rtl::Reference<XMLPropertySetMapper>& rPropertySetMapper(
2683
0
        xExpPropMapper->getPropertySetMapper());
2684
0
    if (!xInfo.is() || !xPropState.is() || !rPropertySetMapper.is())
2685
0
        return;
2686
2687
0
    struct API2ODFMapItem
2688
0
    {
2689
0
        OUString sAPIName;
2690
0
        sal_uInt16 nNameSpace; // from include/xmloff/xmlnamespace.hxx
2691
0
        OUString sLocalName;
2692
0
        API2ODFMapItem(OUString sAPI, const sal_uInt16 nNS, OUString sLocal)
2693
0
            : sAPIName(std::move(sAPI))
2694
0
            , nNameSpace(nNS)
2695
0
            , sLocalName(std::move(sLocal))
2696
0
        {
2697
0
        }
2698
0
    };
2699
2700
0
    const API2ODFMapItem aLabelFoo2ODFArray[]
2701
0
        = { API2ODFMapItem(u"LabelBorderStyle"_ustr, XML_NAMESPACE_DRAW, u"stroke"_ustr),
2702
0
            API2ODFMapItem(u"LabelBorderWidth"_ustr, XML_NAMESPACE_SVG, u"stroke-width"_ustr),
2703
0
            API2ODFMapItem(u"LabelBorderColor"_ustr, XML_NAMESPACE_SVG, u"stroke-color"_ustr),
2704
0
            API2ODFMapItem(u"LabelBorderDashName"_ustr, XML_NAMESPACE_DRAW, u"stroke-dash"_ustr),
2705
0
            API2ODFMapItem(u"LabelBorderTransparency"_ustr, XML_NAMESPACE_SVG, u"stroke-opacity"_ustr),
2706
0
            API2ODFMapItem(u"LabelFillStyle"_ustr, XML_NAMESPACE_DRAW, u"fill"_ustr),
2707
0
            API2ODFMapItem(u"LabelFillBackground"_ustr, XML_NAMESPACE_DRAW, u"fill-hatch-solid"_ustr),
2708
0
            API2ODFMapItem(u"LabelFillHatchName"_ustr, XML_NAMESPACE_DRAW, u"fill-hatch-name"_ustr),
2709
0
            API2ODFMapItem(u"LabelFillColor"_ustr, XML_NAMESPACE_DRAW, u"fill-color"_ustr) };
2710
2711
0
    for (const auto& rIt : aLabelFoo2ODFArray)
2712
0
    {
2713
0
        if (!xInfo->hasPropertyByName(rIt.sAPIName)
2714
0
            || xPropState->getPropertyState(rIt.sAPIName) != beans::PropertyState_DIRECT_VALUE)
2715
0
            continue;
2716
0
        sal_Int32 nTargetIndex
2717
0
            = rPropertySetMapper->GetEntryIndex(rIt.nNameSpace, rIt.sLocalName, 0);
2718
0
        if (nTargetIndex < 0)
2719
0
            continue;
2720
0
        XMLPropertyState aDataLabelStateItem(nTargetIndex,
2721
0
                                             xPropSet->getPropertyValue(rIt.sAPIName));
2722
0
        rDataLabelPropertyStates.emplace_back(aDataLabelStateItem);
2723
0
    }
2724
0
}
2725
} // anonymous namespace
2726
2727
void SchXMLExportHelper_Impl::exportSeries(
2728
    const Reference< chart2::XDiagram > & xNewDiagram,
2729
    const awt::Size & rPageSize,
2730
    bool bExportContent,
2731
    bool bHasTwoYAxes )
2732
0
{
2733
0
    Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY );
2734
0
    if( ! xBCooSysCnt.is())
2735
0
        return;
2736
0
    Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2737
2738
0
    OUString aFirstXDomainRange;
2739
0
    OUString aFirstYDomainRange;
2740
2741
0
    std::vector< XMLPropertyState > aPropertyStates;
2742
0
    std::vector< XMLPropertyState > aDataLabelPropertyStates;
2743
2744
0
    const Sequence< Reference< chart2::XCoordinateSystem > >
2745
0
        aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
2746
0
    for( const auto& rCooSys : aCooSysSeq )
2747
0
    {
2748
0
        Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY );
2749
0
        if( ! xCTCnt.is())
2750
0
            continue;
2751
0
        const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
2752
0
        for( const auto& rChartType : aCTSeq )
2753
0
        {
2754
0
            Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY );
2755
0
            if( ! xDSCnt.is())
2756
0
                continue;
2757
            // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
2758
0
            OUString aChartType( rChartType->getChartType());
2759
0
            OUString aLabelRole = rChartType->getRoleOfSequenceForSeriesLabel();
2760
2761
            // special export for stock charts
2762
0
            if ( aChartType == "com.sun.star.chart2.CandleStickChartType" )
2763
0
            {
2764
0
                bool bJapaneseCandleSticks = false;
2765
0
                Reference< beans::XPropertySet > xCTProp( rChartType, uno::UNO_QUERY );
2766
0
                if( xCTProp.is())
2767
0
                    xCTProp->getPropertyValue(u"Japanese"_ustr) >>= bJapaneseCandleSticks;
2768
0
                exportCandleStickSeries(
2769
0
                    xDSCnt->getDataSeries(), xNewDiagram, bJapaneseCandleSticks, bExportContent );
2770
0
                continue;
2771
0
            }
2772
2773
            // export dataseries for current chart-type
2774
0
            Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
2775
0
            for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx )
2776
0
            {
2777
                // export series
2778
0
                Reference< chart2::data::XDataSource > xSource( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY );
2779
0
                if( xSource.is())
2780
0
                {
2781
0
                    std::unique_ptr<SvXMLElementExport> pSeries;
2782
0
                    Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
2783
0
                        xSource->getDataSequences());
2784
0
                    sal_Int32 nMainSequenceIndex = -1;
2785
0
                    sal_Int32 nSeriesLength = 0;
2786
0
                    bool bHasMeanValueLine = false;
2787
0
                    Reference< beans::XPropertySet > xPropSet;
2788
0
                    tLabelValuesDataPair aSeriesLabelValuesPair;
2789
2790
                    // search for main sequence and create a series element
2791
0
                    {
2792
0
                        Reference< chart2::data::XDataSequence > xValuesSeq;
2793
0
                        Reference< chart2::data::XDataSequence > xLabelSeq;
2794
0
                        sal_Int32 nSeqIdx=0;
2795
0
                        for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2796
0
                        {
2797
0
                            Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2798
0
                            if( nMainSequenceIndex==-1 )
2799
0
                            {
2800
0
                                OUString aRole;
2801
0
                                Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2802
0
                                if( xSeqProp.is())
2803
0
                                    xSeqProp->getPropertyValue(u"Role"_ustr) >>= aRole;
2804
                                // "main" sequence
2805
0
                                if( aRole == aLabelRole )
2806
0
                                {
2807
0
                                    xValuesSeq.set( xTempValueSeq );
2808
0
                                    xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2809
0
                                    nMainSequenceIndex = nSeqIdx;
2810
0
                                }
2811
0
                            }
2812
0
                            sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2813
0
                            if( nSeriesLength < nSequenceLength )
2814
0
                                nSeriesLength = nSequenceLength;
2815
0
                        }
2816
2817
                        // have found the main sequence, then xValuesSeq and
2818
                        // xLabelSeq contain those.  Otherwise both are empty
2819
0
                        {
2820
0
                            sal_Int32 nAttachedAxis = chart::ChartAxisAssign::PRIMARY_Y;
2821
                            // get property states for autostyles
2822
0
                            try
2823
0
                            {
2824
0
                                xPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet(
2825
0
                                    aSeriesSeq[nSeriesIdx], mrExport.GetModel() );
2826
0
                            }
2827
0
                            catch( const uno::Exception & )
2828
0
                            {
2829
0
                                TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" );
2830
0
                                continue;
2831
0
                            }
2832
0
                            if( xPropSet.is())
2833
0
                            {
2834
                                // determine attached axis
2835
0
                                try
2836
0
                                {
2837
0
                                    Any aAny( xPropSet->getPropertyValue( u"Axis"_ustr ));
2838
0
                                    aAny >>= nAttachedAxis;
2839
2840
0
                                    aAny = xPropSet->getPropertyValue( u"MeanValue"_ustr );
2841
0
                                    aAny >>= bHasMeanValueLine;
2842
0
                                }
2843
0
                                catch( const beans::UnknownPropertyException & )
2844
0
                                {
2845
0
                                    TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
2846
0
                                }
2847
2848
0
                                const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
2849
0
                                    mrExport.getSaneDefaultVersion());
2850
0
                                if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
2851
0
                                {
2852
0
                                    lcl_exportNumberFormat( u"NumberFormat"_ustr, xPropSet, mrExport );
2853
0
                                    lcl_exportNumberFormat( u"PercentageNumberFormat"_ustr, xPropSet, mrExport );
2854
0
                                }
2855
2856
0
                                if( mxExpPropMapper.is())
2857
0
                                    aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
2858
0
                                if (!maDestShellID.isEmpty() && (!maSrcShellID.isEmpty() || maSrcShellID != maDestShellID))
2859
0
                                {
2860
                                    // Disable link to source number format property when pasting to
2861
                                    // a different doc shell.  These shell ID's should be both empty
2862
                                    // during real ODF export.
2863
0
                                    disableLinkedNumberFormat(aPropertyStates, mxExpPropMapper->getPropertySetMapper());
2864
0
                                }
2865
0
                            }
2866
2867
0
                            if( bExportContent )
2868
0
                            {
2869
0
                                if( bHasTwoYAxes )
2870
0
                                {
2871
0
                                    if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
2872
0
                                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
2873
0
                                    else
2874
0
                                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
2875
0
                                }
2876
2877
                                // write style name
2878
0
                                AddAutoStyleAttribute( aPropertyStates );
2879
2880
0
                                if( xValuesSeq.is())
2881
0
                                    mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS,
2882
0
                                                           lcl_ConvertRange(
2883
0
                                                               xValuesSeq->getSourceRangeRepresentation(),
2884
0
                                                               xNewDoc ));
2885
0
                                else
2886
                                    // #i75297# allow empty series, export empty range to have all ranges on import
2887
0
                                    mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, OUString());
2888
2889
0
                                const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
2890
0
                                    mrExport.getSaneDefaultVersion());
2891
0
                                if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older
2892
0
                                {
2893
0
                                    if (xPropSet.is())
2894
0
                                    {
2895
0
                                        Any aAny = xPropSet->getPropertyValue(u"ShowLegendEntry"_ustr);
2896
0
                                        if (!aAny.get<bool>())
2897
0
                                        {
2898
0
                                            mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
2899
0
                                        }
2900
0
                                    }
2901
0
                                }
2902
2903
0
                                if (xLabelSeq.is())
2904
0
                                {
2905
                                    // Check if the label is direct string value rather than a reference.
2906
0
                                    bool bHasString = false;
2907
0
                                    uno::Reference<beans::XPropertySet> xLSProp(xLabelSeq, uno::UNO_QUERY);
2908
0
                                    if (xLSProp.is())
2909
0
                                    {
2910
0
                                        try
2911
0
                                        {
2912
0
                                            xLSProp->getPropertyValue(u"HasStringLabel"_ustr) >>= bHasString;
2913
0
                                        }
2914
0
                                        catch (const beans::UnknownPropertyException&) {}
2915
0
                                    }
2916
2917
0
                                    OUString aRange = xLabelSeq->getSourceRangeRepresentation();
2918
2919
0
                                    if (bHasString)
2920
0
                                    {
2921
0
                                        mrExport.AddAttribute(
2922
0
                                            XML_NAMESPACE_LO_EXT, XML_LABEL_STRING, aRange);
2923
0
                                    }
2924
0
                                    else
2925
0
                                    {
2926
0
                                        mrExport.AddAttribute(
2927
0
                                            XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS,
2928
0
                                                lcl_ConvertRange(
2929
0
                                                    xLabelSeq->getSourceRangeRepresentation(), xNewDoc));
2930
0
                                    }
2931
0
                                }
2932
2933
0
                                if( xLabelSeq.is() || xValuesSeq.is() )
2934
0
                                    aSeriesLabelValuesPair = tLabelValuesDataPair( xLabelSeq, xValuesSeq );
2935
2936
                                // chart-type for mixed types
2937
0
                                enum XMLTokenEnum eCTToken(
2938
0
                                    SchXMLTools::getTokenByChartType( aChartType, false /* bUseOldNames */ ));
2939
                                //@todo: get token for current charttype
2940
0
                                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS,
2941
0
                                                       mrExport.GetNamespaceMap().GetQNameByKey(
2942
0
                                                           XML_NAMESPACE_CHART, GetXMLToken( eCTToken )));
2943
2944
                                // open series element until end of for loop
2945
0
                                pSeries.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ));
2946
0
                            }
2947
0
                            else    // autostyles
2948
0
                            {
2949
0
                                CollectAutoStyle( std::move(aPropertyStates) );
2950
0
                            }
2951
                            // remove property states for autostyles
2952
0
                            aPropertyStates.clear();
2953
0
                        }
2954
0
                    }
2955
2956
                    // export domain elements if we have a series parent element
2957
0
                    if( pSeries )
2958
0
                    {
2959
                        // domain elements
2960
0
                        if( bExportContent )
2961
0
                        {
2962
0
                            bool bIsScatterChart = aChartType == "com.sun.star.chart2.ScatterChartType";
2963
0
                            bool bIsBubbleChart = aChartType == "com.sun.star.chart2.BubbleChartType";
2964
0
                            Reference< chart2::data::XDataSequence > xYValuesForBubbleChart;
2965
0
                            if( bIsBubbleChart )
2966
0
                            {
2967
0
                                Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, u"values-y"_ustr ) );
2968
0
                                if( xSequence.is() )
2969
0
                                {
2970
0
                                    xYValuesForBubbleChart = xSequence->getValues();
2971
0
                                    if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart, aFirstYDomainRange, mrExport ) )
2972
0
                                        xYValuesForBubbleChart = nullptr;
2973
0
                                }
2974
0
                            }
2975
0
                            if( bIsScatterChart || bIsBubbleChart )
2976
0
                            {
2977
0
                                Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, u"values-x"_ustr ) );
2978
0
                                if( xSequence.is() )
2979
0
                                {
2980
0
                                    Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2981
0
                                    if( lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ) )
2982
0
                                        m_aDataSequencesToExport.emplace_back(
2983
0
                                            uno::Reference< chart2::data::XDataSequence >(), xValues );
2984
0
                                }
2985
0
                                else if( nSeriesIdx==0 )
2986
0
                                {
2987
                                    //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly
2988
0
                                    Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) );
2989
0
                                    if( xCategories.is() )
2990
0
                                    {
2991
0
                                        Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() );
2992
0
                                        if( !lcl_hasNoValuesButText( xValues ) )
2993
0
                                            lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport );
2994
0
                                    }
2995
0
                                }
2996
0
                            }
2997
0
                            if( xYValuesForBubbleChart.is() )
2998
0
                                m_aDataSequencesToExport.emplace_back(
2999
0
                                    uno::Reference< chart2::data::XDataSequence >(), xYValuesForBubbleChart );
3000
0
                        }
3001
0
                    }
3002
3003
                    // add sequences for main sequence after domain sequences,
3004
                    // so that the export of the local table has the correct order
3005
0
                    if( bExportContent &&
3006
0
                        (aSeriesLabelValuesPair.first.is() || aSeriesLabelValuesPair.second.is()))
3007
0
                        m_aDataSequencesToExport.push_back( aSeriesLabelValuesPair );
3008
3009
                    // statistical objects:
3010
                    // regression curves and mean value lines
3011
0
                    if( bHasMeanValueLine &&
3012
0
                        xPropSet.is() &&
3013
0
                        mxExpPropMapper.is() )
3014
0
                    {
3015
0
                        Reference< beans::XPropertySet > xStatProp;
3016
0
                        try
3017
0
                        {
3018
0
                            Any aPropAny( xPropSet->getPropertyValue( u"DataMeanValueProperties"_ustr ));
3019
0
                            aPropAny >>= xStatProp;
3020
0
                        }
3021
0
                        catch( const uno::Exception & )
3022
0
                        {
3023
0
                            TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" );
3024
0
                        }
3025
3026
0
                        if( xStatProp.is() )
3027
0
                        {
3028
0
                            aPropertyStates = mxExpPropMapper->Filter(mrExport, xStatProp);
3029
3030
0
                            if( !aPropertyStates.empty() )
3031
0
                            {
3032
                                // write element
3033
0
                                if( bExportContent )
3034
0
                                {
3035
                                    // add style name attribute
3036
0
                                    AddAutoStyleAttribute( aPropertyStates );
3037
3038
0
                                    SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_MEAN_VALUE, true, true );
3039
0
                                }
3040
0
                                else    // autostyles
3041
0
                                {
3042
0
                                    CollectAutoStyle( std::move(aPropertyStates) );
3043
0
                                }
3044
0
                            }
3045
0
                        }
3046
0
                    }
3047
3048
0
                    if( xPropSet.is() &&
3049
0
                        mxExpPropMapper.is() )
3050
0
                    {
3051
0
                        exportRegressionCurve( aSeriesSeq[nSeriesIdx], rPageSize, bExportContent );
3052
0
                    }
3053
3054
0
                    exportErrorBar( xPropSet,false, bExportContent );   // X ErrorBar
3055
0
                    exportErrorBar( xPropSet,true, bExportContent );    // Y ErrorBar
3056
3057
0
                    exportDataPoints(
3058
0
                        uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ),
3059
0
                        nSeriesLength, xNewDiagram, bExportContent );
3060
3061
0
                    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
3062
0
                        mrExport.getSaneDefaultVersion());
3063
3064
                    // create <chart:data-label> child element if needed.
3065
0
                    if (xPropSet.is() && mxExpPropMapper.is())
3066
0
                    {
3067
                        // Generate style for <chart:data-label> child element
3068
0
                        if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
3069
0
                        {
3070
0
                            lcl_createDataLabelProperties(aDataLabelPropertyStates, xPropSet,
3071
0
                                                          mxExpPropMapper);
3072
0
                        }
3073
0
                    }
3074
0
                    if (bExportContent)
3075
0
                    {
3076
0
                        if (!aDataLabelPropertyStates.empty())
3077
0
                        {
3078
                            // write style name
3079
0
                            AddAutoStyleAttribute(aDataLabelPropertyStates);
3080
                            // Further content does currently not exist for a <chart:data-label>
3081
                            // element as child of a <chart:series>.
3082
0
                            SvXMLElementExport(mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true,
3083
0
                                               true);
3084
0
                        }
3085
0
                    }
3086
0
                    else
3087
0
                    {
3088
                        // add the style for the to be <chart:data-label> too
3089
0
                        if (!aDataLabelPropertyStates.empty())
3090
0
                            CollectAutoStyle(std::move(aDataLabelPropertyStates));
3091
0
                    }
3092
0
                    aDataLabelPropertyStates.clear();
3093
3094
0
                    if (bExportContent && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older
3095
0
                    {
3096
0
                        Sequence< OUString > aSupportedMappings = rChartType->getSupportedPropertyRoles();
3097
0
                        exportPropertyMapping( xSource, aSupportedMappings );
3098
0
                    }
3099
3100
                    // close series element
3101
0
                    pSeries.reset();
3102
0
                }
3103
0
            }
3104
0
            aPropertyStates.clear();
3105
0
            aDataLabelPropertyStates.clear();
3106
0
        }
3107
0
    }
3108
0
}
3109
3110
void SchXMLExportHelper_Impl::exportPropertyMapping(
3111
    const Reference< chart2::data::XDataSource > & xSource, const Sequence< OUString >& rSupportedMappings )
3112
0
{
3113
0
    Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
3114
0
    Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
3115
0
            xSource->getDataSequences());
3116
3117
0
    for(const auto& rSupportedMapping : rSupportedMappings)
3118
0
    {
3119
0
        Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, rSupportedMapping ) );
3120
0
        if(xSequence.is())
3121
0
        {
3122
0
            Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
3123
0
            if( xValues.is())
3124
0
            {
3125
0
                mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_PROPERTY, rSupportedMapping);
3126
0
                mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_CELL_RANGE_ADDRESS,
3127
0
                        lcl_ConvertRange(
3128
0
                            xValues->getSourceRangeRepresentation(),
3129
0
                            xNewDoc ));
3130
0
                SvXMLElementExport( mrExport, XML_NAMESPACE_LO_EXT, XML_PROPERTY_MAPPING, true, true );
3131
3132
                // register range for data table export
3133
0
                m_aDataSequencesToExport.emplace_back(
3134
0
                            uno::Reference< chart2::data::XDataSequence >(), xValues );
3135
0
            }
3136
0
        }
3137
0
    }
3138
0
}
3139
3140
void SchXMLExportHelper_Impl::exportRegressionCurve(
3141
    const Reference< chart2::XDataSeries >& xSeries,
3142
    const awt::Size& rPageSize,
3143
    bool bExportContent )
3144
0
{
3145
0
    OSL_ASSERT( mxExpPropMapper.is());
3146
3147
0
    Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, uno::UNO_QUERY );
3148
0
    if( !xRegressionCurveContainer.is() )
3149
0
        return;
3150
3151
0
    const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
3152
3153
0
    for( const auto& xRegCurve : aRegCurveSeq )
3154
0
    {
3155
0
        std::vector< XMLPropertyState > aEquationPropertyStates;
3156
0
        if (!xRegCurve.is())
3157
0
            continue;
3158
3159
0
        Reference< beans::XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
3160
0
        if( !xProperties.is() )
3161
0
            continue;
3162
3163
0
        Reference< lang::XServiceName > xServiceName( xProperties, uno::UNO_QUERY );
3164
0
        if( !xServiceName.is() )
3165
0
            continue;
3166
3167
0
        bool bShowEquation = false;
3168
0
        bool bShowRSquared = false;
3169
0
        bool bExportEquation = false;
3170
3171
0
        OUString aService = xServiceName->getServiceName();
3172
3173
0
        std::vector<XMLPropertyState> aPropertyStates = mxExpPropMapper->Filter(mrExport, xProperties);
3174
3175
        // Add service name (which is regression type)
3176
0
        sal_Int32 nIndex = GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE);
3177
0
        XMLPropertyState property(nIndex,  uno::Any(aService));
3178
0
        aPropertyStates.push_back(property);
3179
3180
0
        Reference< beans::XPropertySet > xEquationProperties;
3181
0
        xEquationProperties.set( xRegCurve->getEquationProperties() );
3182
0
        if( xEquationProperties.is())
3183
0
        {
3184
0
            xEquationProperties->getPropertyValue( u"ShowEquation"_ustr) >>= bShowEquation;
3185
0
            xEquationProperties->getPropertyValue( u"ShowCorrelationCoefficient"_ustr) >>= bShowRSquared;
3186
3187
0
            bExportEquation = ( bShowEquation || bShowRSquared );
3188
0
            const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(
3189
0
                mrExport.getSaneDefaultVersion());
3190
0
            if (nCurrentVersion < SvtSaveOptions::ODFSVER_012)
3191
0
            {
3192
0
                bExportEquation=false;
3193
0
            }
3194
0
            if( bExportEquation )
3195
0
            {
3196
                // number format
3197
0
                sal_Int32 nNumberFormat = 0;
3198
0
                if( (xEquationProperties->getPropertyValue(u"NumberFormat"_ustr) >>= nNumberFormat ) &&
3199
0
                    nNumberFormat != -1 )
3200
0
                {
3201
0
                    mrExport.addDataStyle( nNumberFormat );
3202
0
                }
3203
0
                aEquationPropertyStates = mxExpPropMapper->Filter(mrExport, xEquationProperties);
3204
0
            }
3205
0
        }
3206
3207
        // write element
3208
0
        if( bExportContent )
3209
0
        {
3210
            // add style name attribute
3211
0
            AddAutoStyleAttribute( aPropertyStates );
3212
3213
0
            SvXMLElementExport aRegressionExport( mrExport, XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, true, true );
3214
0
            if( bExportEquation )
3215
0
            {
3216
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_EQUATION, (bShowEquation ? XML_TRUE : XML_FALSE) );
3217
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, (bShowRSquared ? XML_TRUE : XML_FALSE) );
3218
3219
                // export position
3220
0
                chart2::RelativePosition aRelativePosition;
3221
0
                if( xEquationProperties->getPropertyValue( u"RelativePosition"_ustr ) >>= aRelativePosition )
3222
0
                {
3223
0
                    double fX = aRelativePosition.Primary * rPageSize.Width;
3224
0
                    double fY = aRelativePosition.Secondary * rPageSize.Height;
3225
0
                    awt::Point aPos;
3226
0
                    aPos.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
3227
0
                    aPos.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
3228
0
                    addPosition( aPos );
3229
0
                }
3230
3231
0
                if( !aEquationPropertyStates.empty())
3232
0
                {
3233
0
                    AddAutoStyleAttribute( aEquationPropertyStates );
3234
0
                }
3235
3236
0
                SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_EQUATION, true, true );
3237
0
            }
3238
0
        }
3239
0
        else    // autostyles
3240
0
        {
3241
0
            CollectAutoStyle( std::move(aPropertyStates) );
3242
0
            if( bExportEquation && !aEquationPropertyStates.empty())
3243
0
            {
3244
0
                CollectAutoStyle( std::move(aEquationPropertyStates) );
3245
0
            }
3246
0
        }
3247
0
    }
3248
0
}
3249
3250
void SchXMLExportHelper_Impl::exportErrorBar( const Reference<beans::XPropertySet> &xSeriesProp,
3251
                                              bool bYError, bool bExportContent )
3252
0
{
3253
0
    assert(mxExpPropMapper.is());
3254
3255
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(
3256
0
        mrExport.getSaneDefaultVersion());
3257
3258
    /// Don't export X ErrorBars for older ODF versions.
3259
0
    if (!bYError && nCurrentVersion < SvtSaveOptions::ODFSVER_012)
3260
0
        return;
3261
3262
0
    if (!xSeriesProp.is())
3263
0
        return;
3264
3265
0
    bool bNegative = false, bPositive = false;
3266
0
    sal_Int32 nErrorBarStyle = chart::ErrorBarStyle::NONE;
3267
0
    Reference< beans::XPropertySet > xErrorBarProp;
3268
3269
0
    try
3270
0
    {
3271
0
        Any aAny = xSeriesProp->getPropertyValue( bYError ? u"ErrorBarY"_ustr : u"ErrorBarX"_ustr );
3272
0
        aAny >>= xErrorBarProp;
3273
3274
0
        if ( xErrorBarProp.is() )
3275
0
        {
3276
0
            aAny = xErrorBarProp->getPropertyValue(u"ShowNegativeError"_ustr );
3277
0
            aAny >>= bNegative;
3278
3279
0
            aAny = xErrorBarProp->getPropertyValue(u"ShowPositiveError"_ustr );
3280
0
            aAny >>= bPositive;
3281
3282
0
            aAny = xErrorBarProp->getPropertyValue(u"ErrorBarStyle"_ustr );
3283
0
            aAny >>= nErrorBarStyle;
3284
0
        }
3285
0
    }
3286
0
    catch( const beans::UnknownPropertyException & )
3287
0
    {
3288
0
        TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
3289
0
    }
3290
3291
0
    if( !(nErrorBarStyle != chart::ErrorBarStyle::NONE && (bNegative || bPositive)))
3292
0
        return;
3293
3294
0
    if( bExportContent && nErrorBarStyle == chart::ErrorBarStyle::FROM_DATA )
3295
0
    {
3296
        // register data ranges for error bars for export in local table
3297
0
        ::std::vector< Reference< chart2::data::XDataSequence > > aErrorBarSequences(
3298
0
            lcl_getErrorBarSequences( xErrorBarProp ));
3299
0
        for( const auto& rErrorBarSequence : aErrorBarSequences )
3300
0
        {
3301
0
            m_aDataSequencesToExport.emplace_back(
3302
0
                uno::Reference< chart2::data::XDataSequence >(), rErrorBarSequence );
3303
0
        }
3304
0
    }
3305
3306
0
    std::vector<XMLPropertyState> aPropertyStates = mxExpPropMapper->Filter(mrExport, xErrorBarProp);
3307
3308
0
    if( aPropertyStates.empty() )
3309
0
        return;
3310
3311
    // write element
3312
0
    if( bExportContent )
3313
0
    {
3314
        // add style name attribute
3315
0
        AddAutoStyleAttribute( aPropertyStates );
3316
3317
0
        if (nCurrentVersion >= SvtSaveOptions::ODFSVER_012)
3318
0
            mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, bYError ? XML_Y : XML_X );//#i114149#
3319
0
        SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, true, true );
3320
0
    }
3321
0
    else    // autostyles
3322
0
    {
3323
0
        CollectAutoStyle( std::move(aPropertyStates) );
3324
0
    }
3325
0
}
3326
3327
void SchXMLExportHelper_Impl::exportCandleStickSeries(
3328
    const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
3329
    const Reference< chart2::XDiagram > & xDiagram,
3330
    bool bJapaneseCandleSticks,
3331
    bool bExportContent )
3332
0
{
3333
3334
0
    for( const auto& xSeries : aSeriesSeq )
3335
0
    {
3336
0
        sal_Int32 nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries )
3337
0
            ? chart::ChartAxisAssign::PRIMARY_Y
3338
0
            : chart::ChartAxisAssign::SECONDARY_Y;
3339
3340
0
        Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
3341
0
        if( xSource.is())
3342
0
        {
3343
            // export series in correct order (as we don't store roles)
3344
            // with japanese candlesticks: open, low, high, close
3345
            // otherwise: low, high, close
3346
0
            Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
3347
0
                xSource->getDataSequences());
3348
3349
0
            sal_Int32 nSeriesLength =
3350
0
                lcl_getSequenceLengthByRole( aSeqCnt, u"values-last"_ustr);
3351
3352
0
            if( bExportContent )
3353
0
            {
3354
0
                Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
3355
                //@todo: export data points
3356
3357
                //TODO: moggi: same code three times
3358
                // open
3359
0
                if( bJapaneseCandleSticks )
3360
0
                {
3361
0
                    tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3362
0
                        aSeqCnt, u"values-first"_ustr,  xNewDoc, m_aDataSequencesToExport ));
3363
0
                    if( !aRanges.second.isEmpty())
3364
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3365
0
                    if( !aRanges.first.isEmpty())
3366
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3367
0
                    if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3368
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3369
0
                    else
3370
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3371
0
                    SvXMLElementExport aOpenSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3372
                    // export empty data points
3373
0
                    exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3374
0
                }
3375
3376
                // low
3377
0
                {
3378
0
                    tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3379
0
                        aSeqCnt, u"values-min"_ustr,  xNewDoc, m_aDataSequencesToExport ));
3380
0
                    if( !aRanges.second.isEmpty())
3381
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3382
0
                    if( !aRanges.first.isEmpty())
3383
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3384
0
                    if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3385
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3386
0
                    else
3387
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3388
0
                    SvXMLElementExport aLowSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3389
                    // export empty data points
3390
0
                    exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3391
0
                }
3392
3393
                // high
3394
0
                {
3395
0
                    tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3396
0
                        aSeqCnt, u"values-max"_ustr,  xNewDoc, m_aDataSequencesToExport ));
3397
0
                    if( !aRanges.second.isEmpty())
3398
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3399
0
                    if( !aRanges.first.isEmpty())
3400
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3401
0
                    if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3402
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3403
0
                    else
3404
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3405
0
                    SvXMLElementExport aHighSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3406
                    // export empty data points
3407
0
                    exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3408
0
                }
3409
3410
                // close
3411
0
                {
3412
0
                    tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3413
0
                        aSeqCnt, u"values-last"_ustr,  xNewDoc, m_aDataSequencesToExport ));
3414
0
                    if( !aRanges.second.isEmpty())
3415
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3416
0
                    if( !aRanges.first.isEmpty())
3417
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3418
0
                    if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3419
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3420
0
                    else
3421
0
                        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3422
0
                    SvXMLElementExport aCloseSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3423
                    // export empty data points
3424
0
                    exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3425
0
                }
3426
0
            }
3427
0
            else    // autostyles
3428
0
            {
3429
                // for close series
3430
0
            }
3431
            // remove property states for autostyles
3432
0
        }
3433
0
    }
3434
0
}
3435
3436
void SchXMLExportHelper_Impl::exportDataPoints(
3437
    const uno::Reference< beans::XPropertySet > & xSeriesProperties,
3438
    sal_Int32 nSeriesLength,
3439
    const uno::Reference< chart2::XDiagram > & xDiagram,
3440
    bool bExportContent )
3441
0
{
3442
    // data-points
3443
3444
    // write data-points only if they contain autostyles
3445
    // objects with equal autostyles are grouped using the attribute
3446
    // repeat="number"
3447
3448
    // Note: if only the nth data-point has autostyles there is an element
3449
    // without style and repeat="n-1" attribute written in advance.
3450
3451
    // the sequence aDataPointSeq contains indices of data-points that
3452
    // do have own attributes.  This increases the performance substantially.
3453
3454
    // more performant version for #93600#
3455
0
    if (!mxExpPropMapper.is())
3456
0
        return;
3457
3458
0
    uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
3459
3460
0
    std::vector< XMLPropertyState > aPropertyStates;
3461
0
    std::vector<XMLPropertyState> aDataLabelPropertyStates;
3462
3463
0
    bool bVaryColorsByPoint = false;
3464
0
    Sequence< sal_Int32 > aDataPointSeq;
3465
0
    Sequence<sal_Int32> deletedLegendEntriesSeq;
3466
0
    if( xSeriesProperties.is())
3467
0
    {
3468
0
        xSeriesProperties->getPropertyValue(u"AttributedDataPoints"_ustr) >>= aDataPointSeq;
3469
0
        xSeriesProperties->getPropertyValue(u"VaryColorsByPoint"_ustr) >>= bVaryColorsByPoint;
3470
3471
0
        const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
3472
0
            mrExport.getSaneDefaultVersion());
3473
0
        if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older
3474
0
            xSeriesProperties->getPropertyValue(u"DeletedLegendEntries"_ustr) >>= deletedLegendEntriesSeq;
3475
0
    }
3476
3477
0
    sal_Int32 nSize = aDataPointSeq.getLength();
3478
0
    SAL_WARN_IF( nSize > nSeriesLength, "xmloff.chart", "Too many point attributes" );
3479
3480
0
    const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
3481
0
    sal_Int32 nElement;
3482
0
    Reference< chart2::XColorScheme > xColorScheme;
3483
0
    if( xDiagram.is())
3484
0
        xColorScheme.set( xDiagram->getDefaultColorScheme());
3485
3486
0
    ::std::vector< SchXMLDataPointStruct > aDataPointVector;
3487
3488
0
    sal_Int32 nLastIndex = -1;
3489
3490
    // collect elements
3491
0
    if( bVaryColorsByPoint && xColorScheme.is() )
3492
0
    {
3493
0
        o3tl::sorted_vector< sal_Int32 > aAttrPointSet;
3494
0
        aAttrPointSet.reserve(aDataPointSeq.getLength());
3495
0
        for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
3496
0
            aAttrPointSet.insert( *p );
3497
0
        const auto aEndIt = aAttrPointSet.end();
3498
0
        for( nElement = 0; nElement < nSeriesLength; ++nElement )
3499
0
        {
3500
0
            aPropertyStates.clear();
3501
0
            aDataLabelPropertyStates.clear();
3502
0
            uno::Reference< beans::XPropertySet > xPropSet;
3503
0
            bool bExportNumFmt = false;
3504
0
            if( aAttrPointSet.find( nElement ) != aEndIt )
3505
0
            {
3506
0
                try
3507
0
                {
3508
0
                    xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3509
0
                                xSeries, nElement, mrExport.GetModel() );
3510
0
                    bExportNumFmt = true;
3511
0
                }
3512
0
                catch( const uno::Exception & )
3513
0
                {
3514
0
                    TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3515
0
                }
3516
0
            }
3517
0
            else
3518
0
            {
3519
                // property set only containing the color
3520
0
                xPropSet.set( new ::xmloff::chart::ColorPropertySet(
3521
0
                                    ::Color(ColorTransparency, xColorScheme->getColorByIndex( nElement ))));
3522
0
            }
3523
0
            SAL_WARN_IF( !xPropSet.is(), "xmloff.chart", "Pie Segments should have properties" );
3524
0
            if( xPropSet.is())
3525
0
            {
3526
0
                const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
3527
0
                    mrExport.getSaneDefaultVersion());
3528
0
                if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012 && bExportNumFmt)
3529
0
                {
3530
0
                    lcl_exportNumberFormat( u"NumberFormat"_ustr, xPropSet, mrExport );
3531
0
                    lcl_exportNumberFormat( u"PercentageNumberFormat"_ustr, xPropSet, mrExport );
3532
0
                }
3533
3534
                // Generate style for <chart:data-label> child element
3535
0
                if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
3536
0
                {
3537
0
                    lcl_createDataLabelProperties(aDataLabelPropertyStates, xPropSet,
3538
0
                                                  mxExpPropMapper);
3539
0
                }
3540
3541
0
                if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED)
3542
0
                {
3543
0
                    sal_Int32 nPlacement = 0;
3544
0
                    xPropSet->getPropertyValue(u"LabelPlacement"_ustr) >>= nPlacement;
3545
0
                    if (nPlacement == chart::DataLabelPlacement::CUSTOM)
3546
0
                    {
3547
0
                        xPropSet->setPropertyValue(u"LabelPlacement"_ustr,
3548
0
                                                  uno::Any(chart::DataLabelPlacement::OUTSIDE));
3549
0
                    }
3550
0
                }
3551
3552
0
                aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
3553
0
                if (!aPropertyStates.empty() || !aDataLabelPropertyStates.empty())
3554
0
                {
3555
0
                    if (bExportContent)
3556
0
                    {
3557
                        // write data-point with style
3558
0
                        SchXMLDataPointStruct aPoint;
3559
0
                        if (!aPropertyStates.empty())
3560
0
                        {
3561
0
                            SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart",
3562
0
                                        "Autostyle queue empty!");
3563
0
                            aPoint.maStyleName = maAutoStyleNameQueue.front();
3564
0
                            maAutoStyleNameQueue.pop();
3565
0
                        }
3566
0
                        if (!aDataLabelPropertyStates.empty())
3567
0
                        {
3568
0
                            SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart",
3569
0
                                        "Autostyle queue empty!");
3570
0
                            aPoint.msDataLabelStyleName = maAutoStyleNameQueue.front();
3571
0
                            maAutoStyleNameQueue.pop();
3572
0
                        }
3573
0
                        if(bExportNumFmt)
3574
0
                            aPoint.mCustomLabel = lcl_getCustomLabelField(mrExport, nElement, xSeries);
3575
0
                        aPoint.mCustomLabelPos = lcl_getCustomLabelPosition(mrExport, nElement, xSeries);
3576
3577
0
                        aDataPointVector.push_back(std::move(aPoint));
3578
0
                    }
3579
0
                    else
3580
0
                    {
3581
0
                        if (!aPropertyStates.empty())
3582
0
                            CollectAutoStyle(std::move(aPropertyStates));
3583
0
                        if (!aDataLabelPropertyStates.empty())
3584
0
                            CollectAutoStyle(std::move(aDataLabelPropertyStates));
3585
0
                    }
3586
0
                }
3587
0
            }
3588
0
        }
3589
0
        SAL_WARN_IF( bExportContent && (static_cast<sal_Int32>(aDataPointVector.size()) != nSeriesLength), "xmloff.chart", "not enough data points on content export" );
3590
0
    }
3591
0
    else
3592
0
    {
3593
0
        for (sal_Int32 nCurrIndex : aDataPointSeq)
3594
0
        {
3595
0
            aPropertyStates.clear();
3596
0
            aDataLabelPropertyStates.clear();
3597
            //assuming sorted indices in pPoints
3598
3599
0
            if( nCurrIndex<0 || nCurrIndex>=nSeriesLength )
3600
0
                break;
3601
3602
            // write leading empty data points
3603
0
            if( nCurrIndex - nLastIndex > 1 )
3604
0
            {
3605
0
                SchXMLDataPointStruct aPoint;
3606
0
                aPoint.mnRepeat = nCurrIndex - nLastIndex - 1;
3607
0
                aDataPointVector.push_back(std::move(aPoint));
3608
0
            }
3609
3610
0
            uno::Reference< beans::XPropertySet > xPropSet;
3611
            // get property states
3612
0
            try
3613
0
            {
3614
0
                xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3615
0
                                xSeries, nCurrIndex, mrExport.GetModel() );
3616
0
            }
3617
0
            catch( const uno::Exception & )
3618
0
            {
3619
0
                TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3620
0
            }
3621
0
            if( xPropSet.is())
3622
0
            {
3623
0
                const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
3624
0
                    mrExport.getSaneDefaultVersion());
3625
0
                if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
3626
0
                {
3627
0
                    lcl_exportNumberFormat( u"NumberFormat"_ustr, xPropSet, mrExport );
3628
0
                    lcl_exportNumberFormat( u"PercentageNumberFormat"_ustr, xPropSet, mrExport );
3629
0
                }
3630
3631
                // Generate style for <chart:data-label> child element
3632
0
                if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
3633
0
                {
3634
0
                    lcl_createDataLabelProperties(aDataLabelPropertyStates, xPropSet,
3635
0
                                                  mxExpPropMapper);
3636
0
                }
3637
3638
0
                aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet);
3639
3640
0
                if (!aPropertyStates.empty() || !aDataLabelPropertyStates.empty())
3641
0
                {
3642
0
                    if( bExportContent )
3643
0
                    {
3644
                        // write data-point with style
3645
0
                        SchXMLDataPointStruct aPoint;
3646
0
                        if (!aPropertyStates.empty())
3647
0
                        {
3648
0
                            SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart",
3649
0
                                        "Autostyle queue empty!");
3650
0
                            aPoint.maStyleName = maAutoStyleNameQueue.front();
3651
0
                            maAutoStyleNameQueue.pop();
3652
0
                        }
3653
0
                        aPoint.mCustomLabel = lcl_getCustomLabelField(mrExport, nCurrIndex, xSeries);
3654
0
                        aPoint.mCustomLabelPos = lcl_getCustomLabelPosition(mrExport, nCurrIndex, xSeries);
3655
0
                        if (!aDataLabelPropertyStates.empty())
3656
0
                        {
3657
0
                            SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart",
3658
0
                                        "Autostyle queue empty!");
3659
0
                            aPoint.msDataLabelStyleName = maAutoStyleNameQueue.front();
3660
0
                            maAutoStyleNameQueue.pop();
3661
0
                        }
3662
3663
0
                        aDataPointVector.push_back(std::move(aPoint));
3664
0
                        nLastIndex = nCurrIndex;
3665
0
                    }
3666
0
                    else
3667
0
                    {
3668
0
                        if (!aPropertyStates.empty())
3669
0
                            CollectAutoStyle(std::move(aPropertyStates));
3670
0
                        if (!aDataLabelPropertyStates.empty())
3671
0
                            CollectAutoStyle(std::move(aDataLabelPropertyStates));
3672
0
                    }
3673
0
                    continue;
3674
0
                }
3675
0
            }
3676
3677
            // if we get here the property states are empty
3678
0
            aDataPointVector.push_back(SchXMLDataPointStruct());
3679
3680
0
            nLastIndex = nCurrIndex;
3681
0
        }
3682
        // final empty elements
3683
0
        sal_Int32 nRepeat = nSeriesLength - nLastIndex - 1;
3684
0
        if( nRepeat > 0 )
3685
0
        {
3686
0
            SchXMLDataPointStruct aPoint;
3687
0
            aPoint.mnRepeat = nRepeat;
3688
0
            aDataPointVector.push_back(std::move(aPoint));
3689
0
        }
3690
0
    }
3691
3692
0
    if (!bExportContent)
3693
0
        return;
3694
3695
    // write elements (merge equal ones)
3696
0
    SchXMLDataPointStruct aPoint;
3697
0
    SchXMLDataPointStruct aLastPoint;
3698
3699
    // initialize so that it doesn't matter if
3700
    // the element is counted in the first iteration
3701
0
    aLastPoint.mnRepeat = 0;
3702
0
    sal_Int32 nIndex = 0;
3703
0
    for( const auto& rPoint : aDataPointVector )
3704
0
    {
3705
0
        aPoint = rPoint;
3706
3707
0
        if (aPoint.maStyleName == aLastPoint.maStyleName
3708
0
            && aLastPoint.mCustomLabel.maFields.getLength() < 1
3709
0
            && aLastPoint.mCustomLabelPos.Primary == 0.0
3710
0
            && aLastPoint.mCustomLabelPos.Secondary == 0.0
3711
0
            && aPoint.msDataLabelStyleName == aLastPoint.msDataLabelStyleName)
3712
0
            aPoint.mnRepeat += aLastPoint.mnRepeat;
3713
0
        else if( aLastPoint.mnRepeat > 0 )
3714
0
        {
3715
            // write last element
3716
0
            if( !aLastPoint.maStyleName.isEmpty() )
3717
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName );
3718
3719
0
            if( aLastPoint.mnRepeat > 1 )
3720
0
                mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED,
3721
0
                                    OUString::number( aLastPoint.mnRepeat ));
3722
3723
0
            for (const auto& deletedLegendEntry : deletedLegendEntriesSeq)
3724
0
            {
3725
0
                if (nIndex == deletedLegendEntry)
3726
0
                {
3727
0
                    mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
3728
0
                    break;
3729
0
                }
3730
0
            }
3731
0
            nIndex++;
3732
0
            exportCustomLabelPosition(aLastPoint.mCustomLabelPos); // adds attributes
3733
0
            SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true );
3734
0
            exportCustomLabel(aLastPoint);
3735
0
        }
3736
0
        aLastPoint = aPoint;
3737
0
    }
3738
    // write last element if it hasn't been written in last iteration
3739
0
    if( aPoint.maStyleName != aLastPoint.maStyleName )
3740
0
        return;
3741
3742
0
    if( !aLastPoint.maStyleName.isEmpty() )
3743
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName );
3744
3745
0
    if( aLastPoint.mnRepeat > 1 )
3746
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED,
3747
0
                            OUString::number( aLastPoint.mnRepeat ));
3748
3749
0
    for (const auto& deletedLegendEntry : deletedLegendEntriesSeq)
3750
0
    {
3751
0
        if (nIndex == deletedLegendEntry)
3752
0
        {
3753
0
            mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
3754
0
            break;
3755
0
        }
3756
0
    }
3757
3758
0
    exportCustomLabelPosition(aLastPoint.mCustomLabelPos); // adds attributes
3759
0
    SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true );
3760
0
    exportCustomLabel(aLastPoint);
3761
0
}
3762
3763
void SchXMLExportHelper_Impl::exportCustomLabel(const SchXMLDataPointStruct& rPoint)
3764
0
{
3765
0
    if (rPoint.mCustomLabel.maFields.getLength() < 1 && rPoint.msDataLabelStyleName.isEmpty())
3766
0
        return; // nothing to export
3767
3768
0
    if (!rPoint.msDataLabelStyleName.isEmpty())
3769
0
        mrExport.AddAttribute(XML_NAMESPACE_CHART, XML_STYLE_NAME, rPoint.msDataLabelStyleName);
3770
3771
0
    if (rPoint.mCustomLabel.mbDataLabelsRange)
3772
0
    {
3773
0
        mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_LABELS_CELL_RANGE, rPoint.mCustomLabel.maRange);
3774
0
        mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_LABEL_GUID, rPoint.mCustomLabel.maGuid);
3775
0
    }
3776
    // TODO svg:x and svg:y for <chart:data-label>
3777
0
    SvXMLElementExport aLabelElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true, true);
3778
0
    SvXMLElementExport aPara( mrExport, XML_NAMESPACE_TEXT, XML_P, true, false );
3779
3780
0
    for (const Reference<chart2::XDataPointCustomLabelField>& label : rPoint.mCustomLabel.maFields)
3781
0
    {
3782
        // TODO add style
3783
0
        SvXMLElementExport aSpan( mrExport, XML_NAMESPACE_TEXT, XML_SPAN, true, false);
3784
0
        mrExport.GetDocHandler()->characters(label->getString());
3785
0
    }
3786
0
}
3787
3788
void SchXMLExportHelper_Impl::exportCustomLabelPosition( const chart2::RelativePosition & xCustomLabelPosition)
3789
0
{
3790
0
    if( xCustomLabelPosition.Primary == 0.0 && xCustomLabelPosition.Secondary == 0.0 )
3791
0
        return; // nothing to export
3792
3793
0
    OUStringBuffer aCustomLabelPosString;
3794
0
    ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Primary);
3795
0
    mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_X, aCustomLabelPosString.makeStringAndClear());
3796
3797
0
    ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Secondary);
3798
0
    mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_Y, aCustomLabelPosString.makeStringAndClear());
3799
0
}
3800
3801
void SchXMLExportHelper_Impl::addPosition( const awt::Point & rPosition )
3802
0
{
3803
0
    mrExport.GetMM100UnitConverter().convertMeasureToXML(
3804
0
            msStringBuffer, rPosition.X );
3805
0
    msString = msStringBuffer.makeStringAndClear();
3806
0
    mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, msString );
3807
3808
0
    mrExport.GetMM100UnitConverter().convertMeasureToXML(
3809
0
            msStringBuffer, rPosition.Y );
3810
0
    msString = msStringBuffer.makeStringAndClear();
3811
0
    mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, msString );
3812
0
}
3813
3814
void SchXMLExportHelper_Impl::addPosition( const Reference< drawing::XShape >& xShape )
3815
0
{
3816
0
    if( xShape.is())
3817
0
        addPosition( xShape->getPosition());
3818
0
}
3819
3820
void SchXMLExportHelper_Impl::addSize( const awt::Size & rSize, bool bIsOOoNamespace)
3821
0
{
3822
0
    mrExport.GetMM100UnitConverter().convertMeasureToXML(
3823
0
            msStringBuffer, rSize.Width );
3824
0
    msString = msStringBuffer.makeStringAndClear();
3825
0
    mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG , XML_WIDTH,  msString );
3826
3827
0
    mrExport.GetMM100UnitConverter().convertMeasureToXML(
3828
0
            msStringBuffer, rSize.Height);
3829
0
    msString = msStringBuffer.makeStringAndClear();
3830
0
    mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG, XML_HEIGHT, msString );
3831
0
}
3832
3833
void SchXMLExportHelper_Impl::addSize( const Reference< drawing::XShape >& xShape )
3834
0
{
3835
0
    if( xShape.is())
3836
0
        addSize( xShape->getSize() );
3837
0
}
3838
3839
awt::Size SchXMLExportHelper_Impl::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc )
3840
0
{
3841
0
    awt::Size aSize( 8000, 7000 );
3842
0
    uno::Reference< embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY );
3843
0
    SAL_WARN_IF( !xVisualObject.is(), "xmloff.chart", "need XVisualObject for page size" );
3844
0
    if( xVisualObject.is() )
3845
0
        aSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
3846
3847
0
    return aSize;
3848
0
}
3849
3850
void SchXMLExportHelper_Impl::CollectAutoStyle( std::vector< XMLPropertyState >&& aStates )
3851
0
{
3852
0
    if( !aStates.empty() )
3853
0
        maAutoStyleNameQueue.push( mrAutoStylePool.Add( XmlStyleFamily::SCH_CHART_ID, std::move(aStates) ));
3854
0
}
3855
3856
void SchXMLExportHelper_Impl::CollectAutoTextStyle( const css::uno::Reference< beans::XPropertySet >& xTitlePropSet )
3857
0
{
3858
0
    if (xTitlePropSet.is())
3859
0
    {
3860
0
        Sequence< uno::Reference< chart2::XFormattedString > > xFormattedTitle;
3861
3862
0
        OUString aTitle;
3863
0
        if ((xTitlePropSet->getPropertyValue(u"String"_ustr) >>= aTitle) && !aTitle.isEmpty())
3864
0
            xTitlePropSet->getPropertyValue(u"FormattedStrings"_ustr) >>= xFormattedTitle;
3865
3866
0
        if (xFormattedTitle.hasElements())
3867
0
        {
3868
0
            for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedTitle)
3869
0
            {
3870
0
                Reference< beans::XPropertySet > xRunPropSet(rxFS, uno::UNO_QUERY);
3871
0
                mrExport.GetTextParagraphExport()->Add(XmlStyleFamily::TEXT_TEXT, xRunPropSet);
3872
0
            }
3873
0
        }
3874
0
    }
3875
0
}
3876
3877
void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates )
3878
0
{
3879
0
    if( !aStates.empty() )
3880
0
    {
3881
0
        SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3882
3883
0
        mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME,  maAutoStyleNameQueue.front() );
3884
0
        maAutoStyleNameQueue.pop();
3885
0
    }
3886
0
}
3887
3888
void SchXMLExportHelper_Impl::exportText( const OUString& rText )
3889
0
{
3890
0
    SchXMLTools::exportText( mrExport, rText, false/*bConvertTabsLFs*/ );
3891
0
}
3892
3893
void SchXMLExportHelper_Impl::exportFormattedText( const css::uno::Reference< beans::XPropertySet >& xTitleProps )
3894
0
{
3895
0
    SchXMLTools::exportFormattedText( mrExport, xTitleProps );
3896
0
}
3897
3898
3899
SchXMLExport::SchXMLExport(const Reference<uno::XComponentContext>& xContext,
3900
                           OUString const& implementationName, SvXMLExportFlags nExportFlags)
3901
0
    : SvXMLExport(xContext, implementationName, util::MeasureUnit::CM, ::xmloff::token::XML_CHART,
3902
0
                  nExportFlags)
3903
0
    , maAutoStylePool(new SchXMLAutoStylePoolP(*this))
3904
0
    , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool))
3905
0
{
3906
0
    if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3907
0
        GetNamespaceMap_().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT);
3908
0
}
3909
3910
SchXMLExport::~SchXMLExport()
3911
0
{
3912
0
}
3913
3914
ErrCode SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass )
3915
0
{
3916
0
    maExportHelper->SetSourceShellID(GetSourceShellID());
3917
0
    maExportHelper->SetDestinationShellID(GetDestinationShellID());
3918
3919
0
    Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3920
0
    maExportHelper->m_pImpl->InitRangeSegmentationProperties( xChartDoc );
3921
0
    return SvXMLExport::exportDoc( eClass );
3922
0
}
3923
3924
void SchXMLExport::ExportMasterStyles_()
3925
0
{
3926
    // not available in chart
3927
0
    SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" );
3928
0
}
3929
3930
void SchXMLExport::collectAutoStyles()
3931
0
{
3932
0
    SvXMLExport::collectAutoStyles();
3933
3934
0
    if (mbAutoStylesCollected)
3935
0
        return;
3936
3937
    // there are no styles that require their own autostyles
3938
0
    if( getExportFlags() & SvXMLExportFlags::CONTENT )
3939
0
    {
3940
0
        Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3941
0
        if( xChartDoc.is())
3942
0
        {
3943
0
            maExportHelper->m_pImpl->collectAutoStyles( xChartDoc );
3944
0
        }
3945
0
        else
3946
0
        {
3947
0
            SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3948
0
        }
3949
0
    }
3950
0
    mbAutoStylesCollected = true;
3951
0
}
3952
3953
void SchXMLExport::ExportAutoStyles_()
3954
0
{
3955
0
    collectAutoStyles();
3956
3957
0
    if( getExportFlags() & SvXMLExportFlags::CONTENT )
3958
0
    {
3959
0
        Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3960
0
        if( xChartDoc.is())
3961
0
        {
3962
0
            maExportHelper->m_pImpl->exportAutoStyles();
3963
0
        }
3964
0
        else
3965
0
        {
3966
0
            SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3967
0
        }
3968
0
    }
3969
0
}
3970
3971
void SchXMLExport::ExportContent_()
3972
0
{
3973
0
    Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3974
0
    if( xChartDoc.is())
3975
0
    {
3976
        // determine if data comes from the outside
3977
0
        bool bIncludeTable = true;
3978
3979
0
        Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
3980
0
        if( xNewDoc.is())
3981
0
        {
3982
            // check if we have own data.  If so we must not export the complete
3983
            // range string, as this is our only indicator for having own or
3984
            // external data. @todo: fix this in the file format!
3985
0
            Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
3986
0
            if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
3987
0
            {
3988
0
                bIncludeTable = false;
3989
0
            }
3990
0
        }
3991
0
        else
3992
0
        {
3993
0
            Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY );
3994
0
            if( xServ.is())
3995
0
            {
3996
0
                if( xServ->supportsService( u"com.sun.star.chart.ChartTableAddressSupplier"_ustr ))
3997
0
                {
3998
0
                    Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY );
3999
0
                    if( xProp.is())
4000
0
                    {
4001
0
                        Any aAny;
4002
0
                        try
4003
0
                        {
4004
0
                            OUString sChartAddress;
4005
0
                            aAny = xProp->getPropertyValue( u"ChartRangeAddress"_ustr );
4006
0
                            aAny >>= sChartAddress;
4007
0
                            maExportHelper->m_pImpl->SetChartRangeAddress( sChartAddress );
4008
4009
                            // do not include own table if there are external addresses
4010
0
                            bIncludeTable = sChartAddress.isEmpty();
4011
0
                        }
4012
0
                        catch( const beans::UnknownPropertyException & )
4013
0
                        {
4014
0
                            SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" );
4015
0
                        }
4016
0
                    }
4017
0
                }
4018
0
            }
4019
0
        }
4020
0
        maExportHelper->m_pImpl->exportChart( xChartDoc, bIncludeTable );
4021
0
    }
4022
0
    else
4023
0
    {
4024
0
        SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" );
4025
0
    }
4026
0
}
4027
4028
rtl::Reference< XMLPropertySetMapper > const & SchXMLExport::GetPropertySetMapper() const
4029
0
{
4030
0
    return maExportHelper->m_pImpl->GetPropertySetMapper();
4031
0
}
4032
4033
void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc )
4034
0
{
4035
0
    if( !xChartDoc.is())
4036
0
        return;
4037
4038
0
    try
4039
0
    {
4040
0
        Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
4041
0
        SAL_WARN_IF( !xDataProvider.is(), "xmloff.chart", "No DataProvider" );
4042
0
        if( xDataProvider.is())
4043
0
        {
4044
0
            Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels ));
4045
0
            const Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource ));
4046
0
            OUString sCellRange, sBrokenRange;
4047
0
            bool bBrokenRangeAvailable = false;
4048
0
            for( const auto& rArg : aArgs )
4049
0
            {
4050
0
                if ( rArg.Name == "CellRangeRepresentation" )
4051
0
                    rArg.Value >>= sCellRange;
4052
0
                else if ( rArg.Name == "BrokenCellRangeForExport" )
4053
0
                {
4054
0
                    if( rArg.Value >>= sBrokenRange )
4055
0
                        bBrokenRangeAvailable = true;
4056
0
                }
4057
0
                else if ( rArg.Name == "DataRowSource" )
4058
0
                {
4059
0
                    chart::ChartDataRowSource eRowSource;
4060
0
                    rArg.Value >>= eRowSource;
4061
0
                    mbRowSourceColumns = ( eRowSource == chart::ChartDataRowSource_COLUMNS );
4062
0
                }
4063
0
                else if ( rArg.Name == "SequenceMapping" )
4064
0
                    rArg.Value >>= maSequenceMapping;
4065
0
            }
4066
4067
            // #i79009# For Writer we have to export a broken version of the
4068
            // range, where every row number is not too large, so that older
4069
            // version can correctly read those files.
4070
0
            msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange);
4071
0
            if( !msChartAddress.isEmpty() )
4072
0
            {
4073
                // convert format to XML-conform one
4074
0
                Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY );
4075
0
                if( xConversion.is())
4076
0
                    msChartAddress = xConversion->convertRangeToXML( msChartAddress );
4077
0
            }
4078
0
        }
4079
0
    }
4080
0
    catch( const uno::Exception & )
4081
0
    {
4082
0
        DBG_UNHANDLED_EXCEPTION("xmloff.chart");
4083
0
    }
4084
0
}
4085
4086
// first version: everything goes in one storage
4087
4088
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4089
com_sun_star_comp_Chart_XMLExporter_get_implementation(uno::XComponentContext* pCtx,
4090
                                                       uno::Sequence<uno::Any> const& /*rSeq*/)
4091
0
{
4092
0
    return cppu::acquire(
4093
0
        new SchXMLExport(pCtx, u"SchXMLExport.Compact"_ustr,
4094
0
                         SvXMLExportFlags::ALL
4095
0
                             ^ (SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES
4096
0
                                | SvXMLExportFlags::SCRIPTS)));
4097
0
}
4098
4099
// Oasis format
4100
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4101
com_sun_star_comp_Chart_XMLOasisExporter_get_implementation(uno::XComponentContext* pCtx,
4102
                                                            uno::Sequence<uno::Any> const& /*rSeq*/)
4103
0
{
4104
0
    return cppu::acquire(
4105
0
        new SchXMLExport(pCtx, u"SchXMLExport.Oasis.Compact"_ustr,
4106
0
                         (SvXMLExportFlags::ALL
4107
0
                          ^ (SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES
4108
0
                             | SvXMLExportFlags::SCRIPTS))
4109
0
                             | SvXMLExportFlags::OASIS));
4110
0
}
4111
4112
// multiple storage version: one for content / styles / meta
4113
4114
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4115
com_sun_star_comp_Chart_XMLStylesExporter_get_implementation(
4116
    uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
4117
0
{
4118
0
    return cppu::acquire(new SchXMLExport(pCtx, u"SchXMLExport.Styles"_ustr, SvXMLExportFlags::STYLES));
4119
0
}
4120
4121
// Oasis format
4122
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4123
com_sun_star_comp_Chart_XMLOasisStylesExporter_get_implementation(
4124
    uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
4125
0
{
4126
0
    return cppu::acquire(new SchXMLExport(pCtx, u"SchXMLExport.Oasis.Styles"_ustr,
4127
0
                                          SvXMLExportFlags::STYLES | SvXMLExportFlags::OASIS));
4128
0
}
4129
4130
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4131
com_sun_star_comp_Chart_XMLContentExporter_get_implementation(
4132
    uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
4133
0
{
4134
0
    return cppu::acquire(new SchXMLExport(pCtx, u"SchXMLExport.Content"_ustr,
4135
0
                                          SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT
4136
0
                                              | SvXMLExportFlags::FONTDECLS));
4137
0
}
4138
4139
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4140
com_sun_star_comp_Chart_XMLOasisContentExporter_get_implementation(
4141
    uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
4142
0
{
4143
0
    return cppu::acquire(new SchXMLExport(pCtx, u"SchXMLExport.Oasis.Content"_ustr,
4144
0
                                          SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT
4145
0
                                              | SvXMLExportFlags::FONTDECLS
4146
0
                                              | SvXMLExportFlags::OASIS));
4147
0
}
4148
4149
// Oasis format
4150
4151
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
4152
com_sun_star_comp_Chart_XMLOasisMetaExporter_get_implementation(
4153
    uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
4154
0
{
4155
0
    return cppu::acquire(new SchXMLExport(pCtx, u"SchXMLExport.Oasis.Meta"_ustr,
4156
0
                                          SvXMLExportFlags::META | SvXMLExportFlags::OASIS));
4157
0
}
4158
4159
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */