Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/chart/SchXMLSeries2Context.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 "SchXMLSeries2Context.hxx"
21
#include "SchXMLPlotAreaContext.hxx"
22
#include "SchXMLRegressionCurveObjectContext.hxx"
23
#include "SchXMLPropertyMappingContext.hxx"
24
#include "SchXMLTools.hxx"
25
26
#include <com/sun/star/chart2/XChartDocument.hpp>
27
#include <com/sun/star/chart2/XRegressionCurve.hpp>
28
#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
29
#include <com/sun/star/chart2/data/XDataSink.hpp>
30
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
31
#include <com/sun/star/chart2/RelativePosition.hpp>
32
33
#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
34
#include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
35
#include <com/sun/star/chart2/DataPointCustomLabelField.hpp>
36
37
#include <com/sun/star/chart/ChartAxisAssign.hpp>
38
#include <com/sun/star/chart/ChartSymbolType.hpp>
39
#include <com/sun/star/chart/ChartDataCaption.hpp>
40
#include <com/sun/star/chart/ErrorBarStyle.hpp>
41
#include <com/sun/star/chart/XChartDocument.hpp>
42
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
43
#include <com/sun/star/chart/ChartLegendPosition.hpp>
44
#include <com/sun/star/embed/Aspects.hpp>
45
#include <com/sun/star/embed/XVisualObject.hpp>
46
47
#include <comphelper/processfactory.hxx>
48
49
#include <sal/log.hxx>
50
#include <utility>
51
#include <xmloff/xmlnamespace.hxx>
52
#include <xmloff/xmlimp.hxx>
53
#include <xmloff/namespacemap.hxx>
54
#include <xmloff/SchXMLSeriesHelper.hxx>
55
#include <xmloff/prstylei.hxx>
56
#include <comphelper/diagnose_ex.hxx>
57
58
#include <algorithm> // std::find_if
59
60
using namespace ::com::sun::star;
61
using namespace ::xmloff::token;
62
63
using ::com::sun::star::uno::Reference;
64
using ::com::sun::star::uno::Sequence;
65
66
namespace
67
{
68
69
class SchXMLDomain2Context : public SvXMLImportContext
70
{
71
private:
72
    ::std::vector< OUString > & mrAddresses;
73
74
public:
75
    SchXMLDomain2Context( SvXMLImport& rImport,
76
                          ::std::vector< OUString > & rAddresses );
77
    virtual void SAL_CALL startFastElement(
78
        sal_Int32 nElement,
79
        const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
80
};
81
82
SchXMLDomain2Context::SchXMLDomain2Context(
83
    SvXMLImport& rImport,
84
    ::std::vector< OUString > & rAddresses ) :
85
0
        SvXMLImportContext( rImport ),
86
0
        mrAddresses( rAddresses )
87
0
{
88
0
}
89
90
void SchXMLDomain2Context::startFastElement(
91
    sal_Int32 /*nElement*/,
92
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
93
0
{
94
0
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
95
0
    {
96
0
        if (aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) )
97
0
            mrAddresses.push_back( aIter.toString() );
98
0
        else
99
0
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
100
0
    }
101
0
}
102
103
void lcl_setAutomaticSymbolSize( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
104
0
{
105
0
    awt::Size aSymbolSize(140,140);//old default for standard sized charts 7cm height
106
107
0
    uno::Reference< chart::XChartDocument > xChartDoc( rImport.GetModel(), uno::UNO_QUERY );
108
0
    if( xChartDoc.is() )
109
0
    {
110
0
        double fScale = 1;
111
0
        uno::Reference< beans::XPropertySet > xLegendProp( xChartDoc->getLegend(), uno::UNO_QUERY );
112
0
        chart::ChartLegendPosition aLegendPosition = chart::ChartLegendPosition_NONE;
113
0
        if( xLegendProp.is() && (xLegendProp->getPropertyValue(u"Alignment"_ustr) >>= aLegendPosition)
114
0
            && chart::ChartLegendPosition_NONE != aLegendPosition )
115
0
        {
116
117
0
            double fFontHeight = 6.0;
118
0
            if( xLegendProp->getPropertyValue(u"CharHeight"_ustr) >>= fFontHeight )
119
0
                fScale = 0.75*fFontHeight/6.0;
120
0
        }
121
0
        else
122
0
        {
123
0
            uno::Reference< embed::XVisualObject > xVisualObject( rImport.GetModel(), uno::UNO_QUERY );
124
0
            if( xVisualObject.is() )
125
0
            {
126
0
                awt::Size aPageSize( xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
127
0
                fScale = aPageSize.Height/7000.0;
128
0
            }
129
0
        }
130
0
        if( fScale>0 )
131
0
        {
132
0
            aSymbolSize.Height = static_cast<sal_Int32>( fScale * aSymbolSize.Height );
133
0
            aSymbolSize.Width = aSymbolSize.Height;
134
0
        }
135
0
    }
136
0
    xSeriesOrPointProp->setPropertyValue(u"SymbolSize"_ustr,uno::Any( aSymbolSize ));
137
0
}
138
139
void lcl_setSymbolSizeIfNeeded( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
140
0
{
141
0
    if( !xSeriesOrPointProp.is() )
142
0
        return;
143
144
0
    sal_Int32 nSymbolType = chart::ChartSymbolType::NONE;
145
0
    if( !(xSeriesOrPointProp.is() && ( xSeriesOrPointProp->getPropertyValue(u"SymbolType"_ustr) >>= nSymbolType)) )
146
0
        return;
147
148
0
    if(chart::ChartSymbolType::NONE!=nSymbolType)
149
0
    {
150
0
        if( chart::ChartSymbolType::BITMAPURL==nSymbolType )
151
0
        {
152
            //set special size for graphics to indicate to use the bitmap size itself
153
0
            xSeriesOrPointProp->setPropertyValue(u"SymbolSize"_ustr,uno::Any( awt::Size(-1,-1) ));
154
0
        }
155
0
        else
156
0
        {
157
0
            lcl_setAutomaticSymbolSize( xSeriesOrPointProp, rImport );
158
0
        }
159
0
    }
160
0
}
161
162
void lcl_resetSymbolSizeForPointsIfNecessary( const uno::Reference< beans::XPropertySet >& xPointProp, const SvXMLImport& rImport
163
    , const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
164
0
{
165
0
    uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize", pPropStyleContext, pStylesCtxt ) );
166
0
    if( !aASymbolSize.hasValue() )
167
0
        lcl_setSymbolSizeIfNeeded( xPointProp, rImport );
168
0
}
169
170
void lcl_setLinkNumberFormatToSourceIfNeeded( const uno::Reference< beans::XPropertySet >& xPointProp
171
    , const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
172
0
{
173
0
    uno::Any aAny( SchXMLTools::getPropertyFromContext(u"LinkNumberFormatToSource", pPropStyleContext, pStylesCtxt) );
174
0
    if( aAny.hasValue() )
175
0
        return;
176
177
0
    if( !xPointProp.is() )
178
0
        return;
179
180
0
    bool bLinkToSource = false;
181
0
    if( xPointProp.is() && (xPointProp->getPropertyValue(u"LinkNumberFormatToSource"_ustr) >>= bLinkToSource) )
182
0
    {
183
0
        if( bLinkToSource )
184
0
        {
185
0
            xPointProp->setPropertyValue(u"LinkNumberFormatToSource"_ustr, uno::Any(false));
186
0
        }
187
0
    }
188
0
}
189
190
void lcl_insertErrorBarLSequencesToMap(
191
    tSchXMLLSequencesPerIndex & rInOutMap,
192
    const uno::Reference< beans::XPropertySet > & xSeriesProp )
193
0
{
194
0
    Reference< chart2::data::XDataSource > xErrorBarSource;
195
0
    if( ( xSeriesProp->getPropertyValue( u"ErrorBarY"_ustr ) >>= xErrorBarSource ) &&
196
0
        xErrorBarSource.is() )
197
0
    {
198
0
        const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences(
199
0
            xErrorBarSource->getDataSequences());
200
0
        for( const auto& rLSequence : aLSequences )
201
0
        {
202
            // use "0" as data index. This is ok, as it is not used for error bars
203
0
            rInOutMap.emplace(
204
0
                    tSchXMLIndexWithPart( 0, SCH_XML_PART_ERROR_BARS ), rLSequence );
205
0
        }
206
0
    }
207
0
}
208
209
Reference< chart2::data::XLabeledDataSequence2 > lcl_createAndAddSequenceToSeries( const OUString& rRole
210
        , const OUString& rRange
211
        , const Reference< chart2::XChartDocument >& xChartDoc
212
        , const Reference< chart2::XDataSeries >& xSeries )
213
0
{
214
0
    Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq;
215
216
0
    Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY );
217
0
    Reference< chart2::data::XDataSink > xSeriesSink( xSeries, uno::UNO_QUERY );
218
219
0
    if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is() && xSeriesSink.is()) )
220
0
        return xLabeledSeq;
221
222
    // create a new sequence
223
0
    xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence();
224
225
    // set values at the new sequence
226
0
    Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc );
227
0
    Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY );
228
0
    if( xSeqProp.is())
229
0
        xSeqProp->setPropertyValue(u"Role"_ustr, uno::Any( rRole));
230
0
    xLabeledSeq->setValues( xSeq );
231
232
    // add new sequence to data series / push to front to have the correct sequence order if charttype is changed afterwards
233
0
    const Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeq( xSeriesSource->getDataSequences());
234
0
    sal_Int32 nOldCount = aOldSeq.getLength();
235
0
    Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeq( nOldCount + 1 );
236
0
    auto pNewSeq = aNewSeq.getArray();
237
0
    pNewSeq[0].set(xLabeledSeq, uno::UNO_QUERY_THROW);
238
0
    std::copy(aOldSeq.begin(), aOldSeq.end(), std::next(pNewSeq));
239
0
    xSeriesSink->setData( aNewSeq );
240
241
0
    return xLabeledSeq;
242
0
}
243
244
XMLPropStyleContext* lcl_GetStylePropContext(
245
                        const SvXMLStylesContext* pStylesCtxt,
246
                        const SvXMLStyleContext*& rpStyle,
247
                        OUString const & rStyleName )
248
0
{
249
0
    rpStyle = pStylesCtxt->FindStyleChildContext( SchXMLImportHelper::GetChartFamilyID(), rStyleName );
250
0
    XMLPropStyleContext* pPropStyleContext =
251
0
                    const_cast< XMLPropStyleContext* >(dynamic_cast< const XMLPropStyleContext* >( rpStyle ));
252
0
    return pPropStyleContext;
253
0
}
254
255
} // anonymous namespace
256
257
SchXMLSeries2Context::SchXMLSeries2Context(
258
    SchXMLImportHelper& rImpHelper,
259
    SvXMLImport& rImport,
260
    const Reference< chart2::XChartDocument > & xNewDoc,
261
    std::vector< SchXMLAxis >& rAxes,
262
    ::std::vector< DataRowPointStyle >& rStyleVector,
263
    ::std::vector< RegressionStyle >& rRegressionStyleVector,
264
    sal_Int32 nSeriesIndex,
265
    bool bStockHasVolume,
266
    GlobalSeriesImportInfo& rGlobalSeriesImportInfo,
267
    const OUString & aGlobalChartTypeName,
268
    tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
269
    bool& rGlobalChartTypeUsedBySeries,
270
    const awt::Size & rChartSize ) :
271
0
        SvXMLImportContext( rImport ),
272
0
        mrImportHelper( rImpHelper ),
273
0
        mxNewDoc( xNewDoc ),
274
0
        mrAxes( rAxes ),
275
0
        mrStyleVector( rStyleVector ),
276
0
        mrRegressionStyleVector( rRegressionStyleVector ),
277
0
        mnSeriesIndex( nSeriesIndex ),
278
0
        mnDataPointIndex( 0 ),
279
0
        m_bStockHasVolume( bStockHasVolume ),
280
0
        m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo),
281
0
        mpAttachedAxis( nullptr ),
282
0
        mnAttachedAxis( 0 ),
283
0
        maGlobalChartTypeName( aGlobalChartTypeName ),
284
0
        maSeriesChartTypeName( aGlobalChartTypeName ),
285
0
        m_bHasDomainContext(false),
286
0
        mrLSequencesPerIndex( rLSequencesPerIndex ),
287
0
        mrGlobalChartTypeUsedBySeries( rGlobalChartTypeUsedBySeries ),
288
0
        mbSymbolSizeIsMissingInFile(false),
289
0
        maChartSize( rChartSize ),
290
        // A series manages the DataRowPointStyle-struct of a data-label child element.
291
0
        mDataLabel(DataRowPointStyle::DATA_LABEL_SERIES, OUString{})
292
0
{
293
0
    if( aGlobalChartTypeName == "com.sun.star.chart2.DonutChartType" )
294
0
    {
295
0
        maSeriesChartTypeName = "com.sun.star.chart2.PieChartType";
296
0
        maGlobalChartTypeName = maSeriesChartTypeName;
297
0
    }
298
0
}
299
300
SchXMLSeries2Context::~SchXMLSeries2Context()
301
0
{
302
0
    SAL_WARN_IF( !maPostponedSequences.empty(), "xmloff.chart", "maPostponedSequences is NULL");
303
0
}
304
305
void SchXMLSeries2Context::startFastElement (sal_Int32 /*Element*/,
306
        const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
307
0
{
308
    // parse attributes
309
0
    mnAttachedAxis = 1;
310
311
0
    bool bHasRange = false;
312
0
    OUString aSeriesLabelRange;
313
0
    OUString aSeriesLabelString;
314
0
    bool bHideLegend = false;
315
316
0
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
317
0
    {
318
0
        OUString aValue = aIter.toString();
319
0
        switch(aIter.getToken())
320
0
        {
321
0
            case XML_ELEMENT(CHART, XML_VALUES_CELL_RANGE_ADDRESS):
322
0
                m_aSeriesRange = aValue;
323
0
                bHasRange = true;
324
0
                break;
325
0
            case XML_ELEMENT(CHART, XML_LABEL_CELL_ADDRESS):
326
0
                aSeriesLabelRange = aValue;
327
0
                break;
328
0
            case XML_ELEMENT(LO_EXT, XML_LABEL_STRING):
329
0
                aSeriesLabelString = aValue;
330
0
                break;
331
0
            case XML_ELEMENT(CHART, XML_ATTACHED_AXIS):
332
0
                {
333
0
                    sal_Int32 nNumOfAxes = mrAxes.size();
334
0
                    for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ )
335
0
                    {
336
0
                        if( aValue == mrAxes[ nCurrent ].aName &&
337
0
                            mrAxes[ nCurrent ].eDimension == SCH_XML_AXIS_Y )
338
0
                        {
339
0
                            mpAttachedAxis = &( mrAxes[ nCurrent ] );
340
0
                        }
341
0
                    }
342
0
                }
343
0
                break;
344
0
            case XML_ELEMENT(CHART, XML_STYLE_NAME):
345
0
                msAutoStyleName = aValue;
346
0
                break;
347
0
            case XML_ELEMENT(CHART, XML_CLASS):
348
0
                {
349
0
                    OUString aClassName;
350
0
                    sal_uInt16 nClassPrefix =
351
0
                        GetImport().GetNamespaceMap().GetKeyByAttrValueQName(
352
0
                            aValue, &aClassName );
353
0
                    if( XML_NAMESPACE_CHART == nClassPrefix )
354
0
                        maSeriesChartTypeName = SchXMLTools::GetChartTypeByClassName( aClassName, false /* bUseOldNames */ );
355
356
0
                    if( maSeriesChartTypeName.isEmpty())
357
0
                        maSeriesChartTypeName = aClassName;
358
0
                }
359
0
                break;
360
0
            case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND):
361
0
                bHideLegend = aValue.toBoolean();
362
0
                break;
363
0
            default:
364
0
                XMLOFF_WARN_UNKNOWN("xmloff", aIter);
365
0
        }
366
0
    }
367
368
0
    if( mpAttachedAxis )
369
0
    {
370
0
        if( mpAttachedAxis->nAxisIndex > 0 )
371
0
        {
372
            // secondary axis => property has to be set (primary is default)
373
0
            mnAttachedAxis = 2;
374
0
        }
375
0
    }
376
377
0
    try
378
0
    {
379
0
        SAL_WARN_IF( !mxNewDoc.is(), "xmloff.chart", "mxNewDoc is NULL");
380
0
        if( m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && ! bHasRange )
381
0
            m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable = false;
382
383
0
        bool bIsCandleStick = maGlobalChartTypeName == "com.sun.star.chart2.CandleStickChartType";
384
0
        if( !maSeriesChartTypeName.isEmpty() )
385
0
        {
386
0
            bIsCandleStick = maSeriesChartTypeName == "com.sun.star.chart2.CandleStickChartType";
387
0
        }
388
0
        else
389
0
        {
390
0
            if( bIsCandleStick
391
0
                && m_bStockHasVolume
392
0
                && mnSeriesIndex == 0 )
393
0
            {
394
0
                maSeriesChartTypeName = "com.sun.star.chart2.ColumnChartType";
395
0
                bIsCandleStick = false;
396
0
            }
397
0
            else
398
0
            {
399
0
                maSeriesChartTypeName = maGlobalChartTypeName;
400
0
            }
401
0
        }
402
0
        if( ! mrGlobalChartTypeUsedBySeries )
403
0
            mrGlobalChartTypeUsedBySeries = (maSeriesChartTypeName == maGlobalChartTypeName);
404
0
        sal_Int32 const nCoordinateSystemIndex = 0;//so far we can only import one coordinate system
405
0
        m_xSeries.set(
406
0
            SchXMLImportHelper::GetNewDataSeries( mxNewDoc, nCoordinateSystemIndex, maSeriesChartTypeName, ! mrGlobalChartTypeUsedBySeries ));
407
0
        Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( SchXMLTools::GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW );
408
409
0
        Reference< beans::XPropertySet > xSeriesProp( m_xSeries, uno::UNO_QUERY );
410
0
        if (xSeriesProp.is())
411
0
        {
412
0
            if (bHideLegend)
413
0
                xSeriesProp->setPropertyValue(u"ShowLegendEntry"_ustr, uno::Any(false));
414
415
0
            if( bIsCandleStick )
416
0
            {
417
                // set default color for range-line to black (before applying styles)
418
0
                xSeriesProp->setPropertyValue(u"Color"_ustr,
419
0
                        uno::Any( sal_Int32( 0x000000 ))); // black
420
0
            }
421
0
            else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" )
422
0
            {
423
                //@todo: this property should be saved
424
0
                xSeriesProp->setPropertyValue(u"VaryColorsByPoint"_ustr,
425
0
                        uno::Any( true ));
426
0
            }
427
428
0
        }
429
430
0
        Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider());
431
0
        Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY);
432
433
0
        Reference<chart2::data::XDataSequence> xSequenceValues;
434
435
        // values
436
0
        if (xPivotTableDataProvider.is()) // is pivot chart
437
0
        {
438
0
            xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex));
439
0
        }
440
0
        else
441
0
        {
442
0
            if (bHasRange && !m_aSeriesRange.isEmpty())
443
0
                xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc);
444
0
        }
445
446
0
        Reference<beans::XPropertySet> xSeqProp(xSequenceValues, uno::UNO_QUERY);
447
0
        if (xSeqProp.is())
448
0
        {
449
0
            OUString aMainRole(u"values-y"_ustr);
450
0
            if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType")
451
0
                aMainRole = "values-size";
452
0
            xSeqProp->setPropertyValue(u"Role"_ustr, uno::Any(aMainRole));
453
0
        }
454
0
        xLabeledSeq->setValues(xSequenceValues);
455
456
        // register for setting local data if external data provider is not present
457
0
        maPostponedSequences.emplace(
458
0
                tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq );
459
460
        // label
461
0
        Reference<chart2::data::XDataSequence> xSequenceLabel;
462
463
0
        if (xPivotTableDataProvider.is())
464
0
        {
465
0
            xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex));
466
0
        }
467
0
        else
468
0
        {
469
0
            if (!aSeriesLabelRange.isEmpty())
470
0
            {
471
0
                xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc));
472
0
            }
473
0
            else if (!aSeriesLabelString.isEmpty())
474
0
            {
475
0
                xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc));
476
0
            }
477
0
        }
478
479
        //Labels should always include hidden cells
480
0
        Reference<beans::XPropertySet> xSeqLabelProp(xSequenceLabel, uno::UNO_QUERY);
481
0
        if (xSeqLabelProp.is() && xSeqLabelProp->getPropertySetInfo()->hasPropertyByName(u"IncludeHiddenCells"_ustr))
482
0
        {
483
0
            xSeqLabelProp->setPropertyValue( u"IncludeHiddenCells"_ustr, uno::Any(true));
484
0
        }
485
486
0
        xLabeledSeq->setLabel(xSequenceLabel);
487
488
        // Note: Even if we have no label, we have to register the label
489
        // for creation, because internal data always has labels. If
490
        // they don't exist in the original, auto-generated labels are
491
        // used for the internal data.
492
0
        maPostponedSequences.emplace(
493
0
                tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_LABEL ), xLabeledSeq );
494
495
0
        Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( &xLabeledSeq, 1 );
496
0
        Reference< chart2::data::XDataSink > xSink( m_xSeries, uno::UNO_QUERY_THROW );
497
0
        xSink->setData( aSeq );
498
0
    }
499
0
    catch( const uno::Exception &)
500
0
    {
501
0
        DBG_UNHANDLED_EXCEPTION("xmloff.chart");
502
0
    }
503
504
    //init mbSymbolSizeIsMissingInFile:
505
0
    try
506
0
    {
507
0
        if( !msAutoStyleName.isEmpty() )
508
0
        {
509
0
            const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
510
0
            if( pStylesCtxt )
511
0
            {
512
0
                const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
513
0
                    SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName );
514
515
0
                const XMLPropStyleContext* pPropStyleContext = dynamic_cast< const XMLPropStyleContext * >( pStyle );
516
517
0
                uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize"
518
0
                    , pPropStyleContext, pStylesCtxt ) );
519
0
                mbSymbolSizeIsMissingInFile = !aASymbolSize.hasValue();
520
0
            }
521
0
        }
522
0
    }
523
0
    catch( const uno::Exception & )
524
0
    {
525
0
    }
526
0
}
527
528
namespace {
529
530
struct DomainInfo
531
{
532
    DomainInfo( OUString _aRole, OUString _aRange, sal_Int32 nIndex )
533
0
        : aRole(std::move(_aRole)), aRange(std::move(_aRange)), nIndexForLocalData(nIndex)
534
0
    {}
535
536
    OUString aRole;
537
    OUString aRange;
538
    sal_Int32 nIndexForLocalData;
539
};
540
541
}
542
543
void SchXMLSeries2Context::endFastElement(sal_Int32 )
544
0
{
545
    // special handling for different chart types.  This is necessary as the
546
    // roles are not yet saved in the file format
547
0
    sal_Int32 nDomainCount = maDomainAddresses.size();
548
0
    bool bIsScatterChart = maSeriesChartTypeName == "com.sun.star.chart2.ScatterChartType";
549
0
    bool bIsBubbleChart = maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType";
550
0
    bool bDeleteSeries = false;
551
0
    std::vector< DomainInfo > aDomainInfos;
552
553
    //different handling for different chart types necessary
554
0
    if( bIsScatterChart || ( nDomainCount==1 && !bIsBubbleChart ) )
555
0
    {
556
0
        DomainInfo aDomainInfo( u"values-x"_ustr, m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
557
0
        bool bCreateXValues = true;
558
0
        if( !maDomainAddresses.empty() )
559
0
        {
560
0
            if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
561
0
            {
562
0
                m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
563
0
                m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
564
0
            }
565
0
            aDomainInfo.aRange = maDomainAddresses.front();
566
0
            aDomainInfo.nIndexForLocalData = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
567
0
            m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
568
0
        }
569
0
        else if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() && !m_bHasDomainContext && mnSeriesIndex==0 )
570
0
        {
571
0
            if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) //wrong old chart files:
572
0
            {
573
                //for xy charts the first series needs to have a domain
574
                //if this by error iss not the case the first series is taken s x values
575
                //needed for wrong files created while having an addin (e.g. BoxPlot)
576
0
                m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = m_aSeriesRange;
577
0
                m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
578
0
                bDeleteSeries = true;
579
0
                bCreateXValues = false;//they will be created for the next series
580
0
            }
581
0
        }
582
0
        if( bCreateXValues )
583
0
            aDomainInfos.push_back( aDomainInfo );
584
0
    }
585
0
    else if( bIsBubbleChart )
586
0
    {
587
0
        if( nDomainCount>1 )
588
0
        {
589
0
            DomainInfo aDomainInfo( u"values-x"_ustr, maDomainAddresses[1], m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
590
0
            if( m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
591
0
            {
592
                //for bubble chart the second domain contains the x values which should become an index smaller than y values for own data table
593
                //->so second first
594
0
                m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress = maDomainAddresses[1];
595
0
                m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
596
0
            }
597
0
            aDomainInfos.push_back( aDomainInfo );
598
0
            m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
599
0
        }
600
0
        else if( !m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
601
0
        {
602
0
            DomainInfo aDomainInfo( u"values-x"_ustr, m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ;
603
0
            aDomainInfos.push_back( aDomainInfo );
604
0
        }
605
0
        if( nDomainCount>0)
606
0
        {
607
0
            DomainInfo aDomainInfo( u"values-y"_ustr, maDomainAddresses.front(), m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
608
0
            if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
609
0
            {
610
0
                m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
611
0
                m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
612
0
            }
613
0
            aDomainInfos.push_back( aDomainInfo );
614
0
            m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
615
0
        }
616
0
        else if( !m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
617
0
        {
618
0
            DomainInfo aDomainInfo( u"values-y"_ustr, m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
619
0
            aDomainInfos.push_back( aDomainInfo );
620
0
        }
621
0
    }
622
623
0
    if( bDeleteSeries )
624
0
    {
625
        //delete created series
626
0
        SchXMLImportHelper::DeleteDataSeries(
627
0
            m_xSeries, Reference< chart2::XChartDocument >( GetImport().GetModel(), uno::UNO_QUERY ) );
628
0
    }
629
0
    else
630
0
    {
631
        //add style
632
0
        if( !msAutoStyleName.isEmpty() || mnAttachedAxis != 1 )
633
0
        {
634
0
            DataRowPointStyle aStyle(
635
0
                DataRowPointStyle::DATA_SERIES,
636
0
                m_xSeries,
637
0
                -1, 1,
638
0
                msAutoStyleName, mnAttachedAxis );
639
0
            aStyle.mbSymbolSizeForSeriesIsMissingInFile=mbSymbolSizeIsMissingInFile;
640
0
            mrStyleVector.push_back(std::move(aStyle));
641
0
        }
642
        // And styles for a data-label child element too. In contrast to data-labels as child of data points,
643
        // an information about absolute position is useless here. We need only style information.
644
0
        if (!mDataLabel.msStyleName.isEmpty())
645
0
        {
646
0
            mDataLabel.msStyleNameOfParent = msAutoStyleName;
647
0
            mDataLabel.m_xSeries = m_xSeries;
648
0
            mDataLabel.mnAttachedAxis = mnAttachedAxis; // not needed, but be consistent with its parent
649
0
            mrStyleVector.push_back(mDataLabel);
650
0
        }
651
0
    }
652
653
0
    for( std::vector< DomainInfo >::reverse_iterator aIt( aDomainInfos.rbegin() ); aIt!= aDomainInfos.rend(); ++aIt )
654
0
    {
655
0
        DomainInfo aDomainInfo( *aIt );
656
0
        Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq =
657
0
            lcl_createAndAddSequenceToSeries( aDomainInfo.aRole, aDomainInfo.aRange, mxNewDoc, m_xSeries );
658
0
        if( xLabeledSeq.is() )
659
0
        {
660
            // register for setting local data if external data provider is not present
661
0
            mrLSequencesPerIndex.emplace(
662
0
                    tSchXMLIndexWithPart( aDomainInfo.nIndexForLocalData, SCH_XML_PART_VALUES ),
663
0
                    Reference< chart2::data::XLabeledDataSequence >(xLabeledSeq, uno::UNO_QUERY_THROW) );
664
0
        }
665
0
    }
666
667
0
    if( !bDeleteSeries )
668
0
    {
669
0
        for (auto const& postponedSequence : maPostponedSequences)
670
0
        {
671
0
            sal_Int32 nNewIndex = postponedSequence.first.first + nDomainCount;
672
0
            mrLSequencesPerIndex.emplace( tSchXMLIndexWithPart( nNewIndex, postponedSequence.first.second ), postponedSequence.second );
673
0
        }
674
0
        m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
675
0
    }
676
0
    maPostponedSequences.clear();
677
0
}
678
679
css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLSeries2Context::createFastChildContext(
680
    sal_Int32 nElement,
681
    const css::uno::Reference< css::xml::sax::XFastAttributeList >&  )
682
0
{
683
0
    SvXMLImportContext* pContext = nullptr;
684
685
0
    switch(nElement)
686
0
    {
687
0
        case XML_ELEMENT(CHART, XML_DOMAIN):
688
0
            if( m_xSeries.is())
689
0
            {
690
0
                m_bHasDomainContext = true;
691
0
                pContext = new SchXMLDomain2Context(
692
0
                    GetImport(), maDomainAddresses );
693
0
            }
694
0
            break;
695
696
0
        case XML_ELEMENT(CHART, XML_MEAN_VALUE):
697
0
            pContext = new SchXMLStatisticsObjectContext(
698
0
                mrImportHelper, GetImport(),
699
0
                msAutoStyleName,
700
0
                mrStyleVector, m_xSeries,
701
0
                SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE,
702
0
                mrLSequencesPerIndex );
703
0
            break;
704
0
        case XML_ELEMENT(CHART, XML_REGRESSION_CURVE):
705
0
            pContext = new SchXMLRegressionCurveObjectContext(
706
0
                mrImportHelper, GetImport(),
707
0
                mrRegressionStyleVector,
708
0
                m_xSeries, maChartSize );
709
0
            break;
710
0
        case XML_ELEMENT(CHART, XML_ERROR_INDICATOR):
711
0
            pContext = new SchXMLStatisticsObjectContext(
712
0
                mrImportHelper, GetImport(),
713
0
                msAutoStyleName,
714
0
                mrStyleVector, m_xSeries,
715
0
                SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR,
716
0
                mrLSequencesPerIndex );
717
0
            break;
718
719
0
        case XML_ELEMENT(CHART, XML_DATA_POINT):
720
0
            pContext = new SchXMLDataPointContext( GetImport(),
721
0
                                                   mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile );
722
0
            break;
723
0
        case XML_ELEMENT(CHART, XML_DATA_LABEL):
724
            // CustomLabels are useless for a data label element as child of a series, because it serves as default
725
            // for all data labels. But the ctor expects it, so use that of the mDataLabel struct as ersatz.
726
0
            pContext = new SchXMLDataLabelContext(GetImport(), mDataLabel.mCustomLabels,
727
0
                                                  mDataLabel);
728
0
            break;
729
730
0
        case XML_ELEMENT(LO_EXT, XML_PROPERTY_MAPPING):
731
0
            pContext = new SchXMLPropertyMappingContext(
732
0
                    GetImport(),
733
0
                    mrLSequencesPerIndex, m_xSeries );
734
0
            break;
735
0
        default:
736
0
            XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
737
0
    }
738
739
0
    return pContext;
740
0
}
741
742
//static
743
void SchXMLSeries2Context::initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
744
        , const uno::Reference< frame::XModel >& xChartModel )
745
0
{
746
    // iterate over series first and remind propertysets in map
747
    // new api <-> old api wrapper
748
0
    ::std::map< Reference< chart2::XDataSeries >, Reference< beans::XPropertySet > > aSeriesMap;
749
0
    for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
750
0
    {
751
0
        if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
752
0
            continue;
753
754
0
        if( !seriesStyle.m_xOldAPISeries.is() )
755
0
            seriesStyle.m_xOldAPISeries = SchXMLSeriesHelper::createOldAPISeriesPropertySet( seriesStyle.m_xSeries, xChartModel );
756
757
0
        aSeriesMap[seriesStyle.m_xSeries] = seriesStyle.m_xOldAPISeries;
758
759
0
    }
760
761
    //initialize m_xOldAPISeries for all other styles also
762
0
    for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
763
0
    {
764
0
        if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES )
765
0
            continue;
766
0
        seriesStyle.m_xOldAPISeries = aSeriesMap[seriesStyle.m_xSeries];
767
0
    }
768
0
}
769
770
//static
771
void SchXMLSeries2Context::setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles )
772
0
{
773
    // iterate over series
774
    // call initSeriesPropertySets first
775
776
0
    for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
777
0
    {
778
0
        if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
779
0
            continue;
780
781
0
        try
782
0
        {
783
0
            uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
784
0
            if( !xSeries.is() )
785
0
                continue;
786
787
0
            if( rSeriesDefaultsAndStyles.maSymbolTypeDefault.hasValue() )
788
0
                xSeries->setPropertyValue(u"SymbolType"_ustr,rSeriesDefaultsAndStyles.maSymbolTypeDefault);
789
0
            if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() )
790
0
                xSeries->setPropertyValue(u"DataCaption"_ustr,rSeriesDefaultsAndStyles.maDataCaptionDefault);
791
792
0
            if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() )
793
0
                xSeries->setPropertyValue(u"ErrorIndicator"_ustr,rSeriesDefaultsAndStyles.maErrorIndicatorDefault);
794
0
            if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() )
795
0
                xSeries->setPropertyValue(u"ErrorCategory"_ustr,rSeriesDefaultsAndStyles.maErrorCategoryDefault);
796
0
            if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() )
797
0
                xSeries->setPropertyValue(u"ConstantErrorLow"_ustr,rSeriesDefaultsAndStyles.maConstantErrorLowDefault);
798
0
            if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() )
799
0
                xSeries->setPropertyValue(u"ConstantErrorHigh"_ustr,rSeriesDefaultsAndStyles.maConstantErrorHighDefault);
800
0
            if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() )
801
0
                xSeries->setPropertyValue(u"PercentageError"_ustr,rSeriesDefaultsAndStyles.maPercentageErrorDefault);
802
0
            if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() )
803
0
                xSeries->setPropertyValue(u"ErrorMargin"_ustr,rSeriesDefaultsAndStyles.maErrorMarginDefault);
804
805
0
            if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() )
806
0
                xSeries->setPropertyValue(u"MeanValue"_ustr,rSeriesDefaultsAndStyles.maMeanValueDefault);
807
0
            if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() )
808
0
                xSeries->setPropertyValue(u"RegressionCurves"_ustr,rSeriesDefaultsAndStyles.maRegressionCurvesDefault);
809
0
        }
810
0
        catch( uno::Exception &  )
811
0
        {
812
            //end of series reached
813
0
        }
814
0
    }
815
0
}
816
817
// ODF has the line and fill properties in a <style:style> element, which is referenced by the
818
// <chart:data-label> element. But LibreOffice has them as special label properties of the series
819
// or point respectively. The following array maps the API name of the ODF property to the name of
820
// the internal property. Those are of kind "LabelFoo".
821
// The array is used in methods setStylesToSeries and setStylesToDataPoints.
822
const std::pair<OUString, OUString> aApiToLabelFooPairs[]
823
    = { { "LineStyle", "LabelBorderStyle" },
824
        { "LineWidth", "LabelBorderWidth" },
825
        { "LineColor", "LabelBorderColor" },
826
        // The name "LabelBorderDash" is defined, but the associated API name "LineDash" belongs to
827
        // the <draw:stroke-dash> element and is not used directly as line property.
828
        //{"LineDash", "LabelBorderDash"},
829
        { "LineDashName", "LabelBorderDashName" },
830
        { "LineTransparence", "LabelBorderTransparency" },
831
        { "FillStyle", "LabelFillStyle" },
832
        { "FillBackground", "LabelFillBackground" },
833
        { "FillHatchName", "LabelFillHatchName" },
834
        { "FillColor", "LabelFillColor" } };
835
836
837
//static
838
void SchXMLSeries2Context::setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
839
        , const SvXMLStylesContext* pStylesCtxt
840
        , const SvXMLStyleContext*& rpStyle
841
        , OUString& rCurrStyleName
842
        , const SchXMLImportHelper& rImportHelper
843
        , const SvXMLImport& rImport
844
        , bool bIsStockChart
845
        , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex )
846
0
{
847
    // iterate over series
848
0
    for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
849
0
    {
850
0
        if (seriesStyle.meType != DataRowPointStyle::DATA_SERIES)
851
0
            continue;
852
0
        try
853
0
        {
854
0
            uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
855
0
            if( !xSeriesProp.is() )
856
0
                continue;
857
858
0
            if( seriesStyle.mnAttachedAxis != 1 )
859
0
            {
860
0
                xSeriesProp->setPropertyValue(u"Axis"_ustr
861
0
                    , uno::Any(chart::ChartAxisAssign::SECONDARY_Y) );
862
0
            }
863
864
0
            if( seriesStyle.msStyleName.isEmpty())
865
0
                continue;
866
867
0
            if( rCurrStyleName != seriesStyle.msStyleName )
868
0
            {
869
0
                rCurrStyleName = seriesStyle.msStyleName;
870
0
                rpStyle = pStylesCtxt->FindStyleChildContext(
871
0
                SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
872
0
            }
873
874
            //set style to series
875
            // note: SvXMLStyleContext::FillPropertySet is not const
876
0
            XMLPropStyleContext * pPropStyleContext =
877
0
                const_cast< XMLPropStyleContext * >(
878
0
                    dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
879
880
0
            if (!pPropStyleContext)
881
0
                continue;
882
883
            // error bar style must be set before the other error
884
            // bar properties (which may be alphabetically before
885
            // this property)
886
0
            bool bHasErrorBarRangesFromData = false;
887
0
            {
888
0
                static constexpr OUString aErrorBarStylePropName( u"ErrorBarStyle"_ustr);
889
0
                uno::Any aErrorBarStyle(
890
0
                    SchXMLTools::getPropertyFromContext( aErrorBarStylePropName, pPropStyleContext, pStylesCtxt ));
891
0
                if( aErrorBarStyle.hasValue())
892
0
                {
893
0
                    xSeriesProp->setPropertyValue( aErrorBarStylePropName, aErrorBarStyle );
894
0
                    sal_Int32 eEBStyle = chart::ErrorBarStyle::NONE;
895
0
                    bHasErrorBarRangesFromData =
896
0
                        ( ( aErrorBarStyle >>= eEBStyle ) &&
897
0
                         eEBStyle == chart::ErrorBarStyle::FROM_DATA );
898
0
                }
899
0
            }
900
901
            //don't set the style to the min max line series of a stock chart
902
            //otherwise the min max line properties gets overwritten and the series becomes invisible typically
903
0
            if (bIsStockChart)
904
0
            {
905
0
                if (SchXMLSeriesHelper::isCandleStickSeries(
906
0
                        seriesStyle.m_xSeries,
907
0
                        rImportHelper.GetChartDocument()))
908
0
                    continue;
909
0
            }
910
911
            // Has the series a data-label child element?
912
0
            auto pItLabel
913
0
                = std::find_if(rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
914
0
                               rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
915
0
                               [&seriesStyle](const DataRowPointStyle& rStyle) {
916
0
                                   return rStyle.meType == DataRowPointStyle::DATA_LABEL_SERIES
917
0
                                          && rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
918
0
                               });
919
0
            if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
920
0
            {
921
                // Bring the information from the data-label to the series
922
0
                const SvXMLStyleContext* pLabelStyleContext(pStylesCtxt->FindStyleChildContext(
923
0
                    SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
924
                // note: SvXMLStyleContext::FillPropertySet is not const
925
0
                XMLPropStyleContext* pLabelPropStyleContext = const_cast<XMLPropStyleContext*>(
926
0
                    dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
927
0
                if (pLabelPropStyleContext)
928
0
                {
929
                    // Test each to be mapped property whether the data-label has a value for it.
930
                    // If found, set it at series.
931
0
                    uno::Reference<beans::XPropertySetInfo> xSeriesPropInfo(
932
0
                        xSeriesProp->getPropertySetInfo());
933
0
                    for (const auto& rPropPair : aApiToLabelFooPairs)
934
0
                    {
935
0
                        uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
936
0
                            rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
937
0
                        if (aPropValue.hasValue()
938
0
                            && xSeriesPropInfo->hasPropertyByName(rPropPair.second))
939
0
                            xSeriesProp->setPropertyValue(rPropPair.second, aPropValue);
940
0
                    }
941
0
                }
942
0
            }
943
944
0
            pPropStyleContext->FillPropertySet( xSeriesProp );
945
0
            if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
946
0
                lcl_setSymbolSizeIfNeeded( xSeriesProp, rImport );
947
0
            if( bHasErrorBarRangesFromData )
948
0
                lcl_insertErrorBarLSequencesToMap( rInOutLSequencesPerIndex, xSeriesProp );
949
950
0
        }
951
0
        catch( const uno::Exception & )
952
0
        {
953
0
                TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
954
0
        }
955
0
    }
956
0
}
957
958
// static
959
void SchXMLSeries2Context::setStylesToRegressionCurves(
960
                                SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles,
961
                                const SvXMLStylesContext* pStylesCtxt,
962
                                const SvXMLStyleContext*& rpStyle,
963
                                OUString const & rCurrentStyleName )
964
0
{
965
    // iterate over regression etc
966
0
    for (auto const& regressionStyle : rSeriesDefaultsAndStyles.maRegressionStyleVector)
967
0
    {
968
0
        try
969
0
        {
970
0
            OUString aServiceName;
971
0
            XMLPropStyleContext* pPropStyleContext = nullptr;
972
973
0
            if (!rCurrentStyleName.isEmpty())
974
0
            {
975
0
                XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, rCurrentStyleName);
976
0
                if( pCurrent )
977
0
                {
978
0
                    pPropStyleContext = pCurrent;
979
0
                    uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
980
0
                    if ( aAny.hasValue() )
981
0
                    {
982
0
                        aAny >>= aServiceName;
983
0
                    }
984
0
                }
985
0
            }
986
987
0
            if (!regressionStyle.msStyleName.isEmpty())
988
0
            {
989
0
                XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, regressionStyle.msStyleName);
990
0
                if( pCurrent )
991
0
                {
992
0
                    pPropStyleContext = pCurrent;
993
0
                    uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
994
0
                    if ( aAny.hasValue() )
995
0
                    {
996
0
                        aAny >>= aServiceName;
997
0
                    }
998
0
                }
999
0
            }
1000
1001
0
            if( !aServiceName.isEmpty() )
1002
0
            {
1003
0
                Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory();
1004
0
                Reference< chart2::XRegressionCurve > xRegCurve( xMSF->createInstance( aServiceName ), uno::UNO_QUERY_THROW );
1005
0
                Reference< chart2::XRegressionCurveContainer > xRegCurveCont( regressionStyle.m_xSeries, uno::UNO_QUERY_THROW );
1006
1007
0
                Reference< beans::XPropertySet > xCurveProperties( xRegCurve, uno::UNO_QUERY );
1008
0
                if( pPropStyleContext != nullptr)
1009
0
                    pPropStyleContext->FillPropertySet( xCurveProperties );
1010
1011
0
                xRegCurve->setEquationProperties( regressionStyle.m_xEquationProperties );
1012
1013
0
                xRegCurveCont->addRegressionCurve( xRegCurve );
1014
0
            }
1015
0
        }
1016
0
        catch( const uno::Exception& )
1017
0
        {
1018
0
            TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
1019
0
        }
1020
1021
0
    }
1022
0
}
1023
1024
// static
1025
void SchXMLSeries2Context::setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
1026
        , const SvXMLStylesContext* pStylesCtxt
1027
        , const SvXMLStyleContext*& rpStyle
1028
        , OUString& rCurrStyleName )
1029
0
{
1030
    // iterate over regression etc
1031
0
    for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
1032
0
    {
1033
0
        if( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR ||
1034
0
            seriesStyle.meType == DataRowPointStyle::MEAN_VALUE )
1035
0
        {
1036
0
            if ( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR )
1037
0
            {
1038
0
                uno::Reference< beans::XPropertySet > xNewSeriesProp(seriesStyle.m_xSeries,uno::UNO_QUERY);
1039
1040
0
                if (seriesStyle.m_xErrorXProperties.is())
1041
0
                    xNewSeriesProp->setPropertyValue(u"ErrorBarX"_ustr,uno::Any(seriesStyle.m_xErrorXProperties));
1042
1043
0
                if (seriesStyle.m_xErrorYProperties.is())
1044
0
                    xNewSeriesProp->setPropertyValue(u"ErrorBarY"_ustr,uno::Any(seriesStyle.m_xErrorYProperties));
1045
0
            }
1046
1047
0
            try
1048
0
            {
1049
0
                uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
1050
0
                if( !xSeriesProp.is() )
1051
0
                    continue;
1052
1053
0
                if( !seriesStyle.msStyleName.isEmpty())
1054
0
                {
1055
0
                    if( rCurrStyleName != seriesStyle.msStyleName )
1056
0
                    {
1057
0
                        rCurrStyleName = seriesStyle.msStyleName;
1058
0
                        rpStyle = pStylesCtxt->FindStyleChildContext(
1059
0
                            SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
1060
0
                    }
1061
1062
                    // note: SvXMLStyleContext::FillPropertySet is not const
1063
0
                    XMLPropStyleContext * pPropStyleContext =
1064
0
                        const_cast< XMLPropStyleContext * >(
1065
0
                            dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
1066
0
                    if( pPropStyleContext )
1067
0
                    {
1068
0
                        Reference< beans::XPropertySet > xStatPropSet;
1069
0
                        switch( seriesStyle.meType )
1070
0
                        {
1071
0
                            case DataRowPointStyle::MEAN_VALUE:
1072
0
                                xSeriesProp->getPropertyValue(u"DataMeanValueProperties"_ustr) >>= xStatPropSet;
1073
0
                                break;
1074
0
                            case DataRowPointStyle::ERROR_INDICATOR:
1075
0
                                xSeriesProp->getPropertyValue(u"DataErrorProperties"_ustr)  >>= xStatPropSet;
1076
0
                                break;
1077
0
                            default:
1078
0
                                break;
1079
0
                        }
1080
0
                        if( xStatPropSet.is())
1081
0
                            pPropStyleContext->FillPropertySet( xStatPropSet );
1082
0
                    }
1083
0
                }
1084
0
            }
1085
0
            catch( const uno::Exception & )
1086
0
            {
1087
0
                TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
1088
0
            }
1089
0
        }
1090
0
    }
1091
0
}
1092
1093
//static
1094
void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
1095
        , const SvXMLStylesContext* pStylesCtxt
1096
        , const SvXMLStyleContext*& rpStyle
1097
        , OUString& rCurrStyleName
1098
        , const SchXMLImportHelper& rImportHelper
1099
        , const SvXMLImport& rImport
1100
        , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter )
1101
0
{
1102
0
    for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
1103
0
    {
1104
0
        if( seriesStyle.meType != DataRowPointStyle::DATA_POINT )
1105
0
            continue;
1106
1107
0
        if( seriesStyle.m_nPointIndex == -1 )
1108
0
            continue;
1109
1110
0
        uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
1111
0
        if(!xSeriesProp.is())
1112
0
            continue;
1113
1114
        //ignore datapoint properties for stock charts
1115
        //... todo ...
1116
0
        if( bIsStockChart )
1117
0
        {
1118
0
            if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries, rImportHelper.GetChartDocument() ) )
1119
0
                continue;
1120
0
        }
1121
1122
        // data point style
1123
0
        for( sal_Int32 i = 0; i < seriesStyle.m_nPointRepeat; i++ )
1124
0
        {
1125
0
            try
1126
0
            {
1127
0
                uno::Reference< beans::XPropertySet > xPointProp(
1128
0
                    SchXMLSeriesHelper::createOldAPIDataPointPropertySet( seriesStyle.m_xSeries, seriesStyle.m_nPointIndex + i
1129
0
                        , rImportHelper.GetChartDocument() ) );
1130
1131
0
                if( !xPointProp.is() )
1132
0
                    continue;
1133
1134
0
                if( bIsDonutChart )
1135
0
                {
1136
                    //set special series styles for donut charts first
1137
0
                    if( rCurrStyleName != seriesStyle.msSeriesStyleNameForDonuts )
1138
0
                    {
1139
0
                        rCurrStyleName = seriesStyle.msSeriesStyleNameForDonuts;
1140
0
                        rpStyle = pStylesCtxt->FindStyleChildContext(
1141
0
                            SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
1142
0
                    }
1143
1144
                    // note: SvXMLStyleContext::FillPropertySet is not const
1145
0
                    XMLPropStyleContext * pPropStyleContext =
1146
0
                        const_cast< XMLPropStyleContext * >(
1147
0
                            dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
1148
0
                    if( pPropStyleContext )
1149
0
                        pPropStyleContext->FillPropertySet( xPointProp );
1150
0
                }
1151
1152
0
                try
1153
0
                {
1154
                    //need to set this explicitly here for old files as the new api does not support this property fully anymore
1155
0
                    if( bSwitchOffLinesForScatter )
1156
0
                        xPointProp->setPropertyValue(u"Lines"_ustr,uno::Any(false));
1157
0
                }
1158
0
                catch( const uno::Exception & )
1159
0
                {
1160
0
                }
1161
1162
0
                if( rCurrStyleName != seriesStyle.msStyleName )
1163
0
                {
1164
0
                    rCurrStyleName = seriesStyle.msStyleName;
1165
0
                    rpStyle = pStylesCtxt->FindStyleChildContext(
1166
0
                        SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
1167
0
                }
1168
1169
                // note: SvXMLStyleContext::FillPropertySet is not const
1170
0
                XMLPropStyleContext * pPropStyleContext =
1171
0
                    const_cast< XMLPropStyleContext * >(
1172
0
                        dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
1173
0
                if (pPropStyleContext)
1174
0
                {
1175
                    // Has the point a data-label child element?
1176
0
                    auto pItLabel = std::find_if(
1177
0
                        rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
1178
0
                        rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
1179
0
                        [&seriesStyle](const DataRowPointStyle& rStyle) {
1180
0
                            return rStyle.meType == DataRowPointStyle::DATA_LABEL_POINT
1181
0
                                   && rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
1182
0
                        });
1183
0
                    if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
1184
0
                    {
1185
                        // Bring the information from the data-label to the point
1186
0
                        const SvXMLStyleContext* pLabelStyleContext(
1187
0
                            pStylesCtxt->FindStyleChildContext(
1188
0
                                SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
1189
                        // note: SvXMLStyleContext::FillPropertySet is not const
1190
0
                        XMLPropStyleContext* pLabelPropStyleContext
1191
0
                            = const_cast<XMLPropStyleContext*>(
1192
0
                                dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
1193
0
                        if (pLabelPropStyleContext)
1194
0
                        {
1195
                            // Test each to be mapped property whether the data-label has a value for it.
1196
                            // If found, set it at the point.
1197
0
                            uno::Reference<beans::XPropertySetInfo> xPointPropInfo(
1198
0
                                xPointProp->getPropertySetInfo());
1199
0
                            for (const auto& rPropPair : aApiToLabelFooPairs)
1200
0
                            {
1201
0
                                uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
1202
0
                                    rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
1203
0
                                if (aPropValue.hasValue()
1204
0
                                    && xPointPropInfo->hasPropertyByName(rPropPair.second))
1205
0
                                    xPointProp->setPropertyValue(rPropPair.second, aPropValue);
1206
0
                            }
1207
0
                        }
1208
0
                    }
1209
1210
0
                    pPropStyleContext->FillPropertySet( xPointProp );
1211
0
                    if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
1212
0
                        lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt );
1213
0
                    if( !pPropStyleContext->isEmptyDataStyleName() )
1214
0
                        lcl_setLinkNumberFormatToSourceIfNeeded( xPointProp, pPropStyleContext, pStylesCtxt );
1215
0
                }
1216
1217
                // Custom labels might be passed as property
1218
0
                if(const size_t nLabelCount = seriesStyle.mCustomLabels.mLabels.size(); nLabelCount > 0)
1219
0
                {
1220
0
                    auto& rCustomLabels = seriesStyle.mCustomLabels;
1221
1222
0
                    Sequence< Reference<chart2::XDataPointCustomLabelField>> xLabels(nLabelCount);
1223
0
                    auto pxLabels = xLabels.getArray();
1224
0
                    const Reference< uno::XComponentContext >& xContext( comphelper::getProcessComponentContext() );
1225
0
                    for( size_t j = 0; j < nLabelCount; ++j )
1226
0
                    {
1227
0
                        Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext);
1228
0
                        pxLabels[j] = xCustomLabel;
1229
0
                        xCustomLabel->setString(rCustomLabels.mLabels[j]);
1230
0
                        if ( j == 0 && rCustomLabels.mbDataLabelsRange)
1231
0
                        {
1232
0
                            xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE);
1233
0
                            xCustomLabel->setGuid(rCustomLabels.msLabelGuid);
1234
0
                            xCustomLabel->setCellRange(rCustomLabels.msLabelsCellRange);
1235
0
                            xCustomLabel->setDataLabelsRange(true);
1236
0
                        }
1237
0
                        else
1238
0
                        {
1239
0
                            xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT);
1240
0
                        }
1241
1242
                        // Restore character properties on the text span manually, till
1243
                        // SchXMLExportHelper_Impl::exportCustomLabel() does not write the style.
1244
0
                        uno::Reference<beans::XPropertySetInfo> xPointPropInfo
1245
0
                            = xPointProp->getPropertySetInfo();
1246
0
                        if (xPointPropInfo.is())
1247
0
                        {
1248
0
                            uno::Sequence<beans::Property> aProperties = xPointPropInfo->getProperties();
1249
0
                            for (const auto& rProperty : aProperties)
1250
0
                            {
1251
0
                                if (!rProperty.Name.startsWith("Char")
1252
0
                                    || rProperty.Name.startsWith("Chart"))
1253
0
                                {
1254
0
                                    continue;
1255
0
                                }
1256
1257
0
                                xCustomLabel->setPropertyValue(
1258
0
                                    rProperty.Name, xPointProp->getPropertyValue(rProperty.Name));
1259
0
                            }
1260
0
                        }
1261
0
                    }
1262
1263
0
                    xPointProp->setPropertyValue(u"CustomLabelFields"_ustr, uno::Any(xLabels));
1264
0
                    xPointProp->setPropertyValue(u"DataCaption"_ustr, uno::Any(chart::ChartDataCaption::CUSTOM));
1265
0
                }
1266
1267
0
                if( seriesStyle.mCustomLabelPos[0] != 0.0 || seriesStyle.mCustomLabelPos[1] != 0.0 )
1268
0
                {
1269
0
                    chart2::RelativePosition aCustomlabelPosition;
1270
0
                    aCustomlabelPosition.Primary = seriesStyle.mCustomLabelPos[0];
1271
0
                    aCustomlabelPosition.Secondary = seriesStyle.mCustomLabelPos[1];
1272
0
                    xPointProp->setPropertyValue(u"CustomLabelPosition"_ustr, uno::Any(aCustomlabelPosition));
1273
0
                }
1274
0
            }
1275
0
            catch( const uno::Exception & )
1276
0
            {
1277
0
                TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to data points" );
1278
0
            }
1279
0
        }
1280
0
    }   // styles iterator
1281
0
}
1282
1283
//static
1284
void SchXMLSeries2Context::switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector )
1285
0
{
1286
    // iterate over series
1287
0
    for (auto const& seriesStyle : rSeriesStyleVector)
1288
0
    {
1289
0
        if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
1290
0
            continue;
1291
1292
0
        try
1293
0
        {
1294
0
            uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
1295
0
            if( !xSeries.is() )
1296
0
                continue;
1297
1298
0
            xSeries->setPropertyValue(u"Lines"_ustr,uno::Any(false));
1299
0
        }
1300
0
        catch( uno::Exception &  )
1301
0
        {
1302
            //end of series reached
1303
0
        }
1304
0
    }
1305
0
}
1306
1307
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */