Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/controller/dialogs/DialogModel.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 "DialogModel.hxx"
21
#include <RangeSelectionHelper.hxx>
22
#include <DataInterpreter.hxx>
23
#include <DataSeries.hxx>
24
#include <DataSeriesHelper.hxx>
25
#include <DataSourceHelper.hxx>
26
#include <Diagram.hxx>
27
#include <strings.hrc>
28
#include <ResId.hxx>
29
#include <ControllerLockGuard.hxx>
30
#include <ChartType.hxx>
31
#include <ChartTypeTemplate.hxx>
32
#include <ThreeDHelper.hxx>
33
#include <ChartModel.hxx>
34
#include <BaseCoordinateSystem.hxx>
35
#include <LabeledDataSequence.hxx>
36
37
#include <com/sun/star/chart2/AxisType.hpp>
38
#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
39
#include <comphelper/diagnose_ex.hxx>
40
41
#include <rtl/ustring.hxx>
42
43
#include <utility>
44
#include <algorithm>
45
#include <cstddef>
46
#include <iterator>
47
#include <numeric>
48
49
using namespace ::com::sun::star;
50
using namespace ::com::sun::star::chart2;
51
52
using ::com::sun::star::uno::Reference;
53
using ::com::sun::star::uno::Sequence;
54
55
namespace
56
{
57
constexpr OUString lcl_aLabelRole( u"label"_ustr );
58
59
60
OUString lcl_ConvertRole( const OUString & rRoleString )
61
0
{
62
0
    OUString aResult( rRoleString );
63
64
0
    typedef std::map< OUString, OUString > tTranslationMap;
65
0
    static const tTranslationMap aTranslationMap =
66
0
    {
67
0
        { "categories", ::chart::SchResId( STR_DATA_ROLE_CATEGORIES ) },
68
0
        { "error-bars-x", ::chart::SchResId( STR_DATA_ROLE_X_ERROR ) },
69
0
        { "error-bars-x-positive", ::chart::SchResId( STR_DATA_ROLE_X_ERROR_POSITIVE ) },
70
0
        { "error-bars-x-negative", ::chart::SchResId( STR_DATA_ROLE_X_ERROR_NEGATIVE ) },
71
0
        { "error-bars-y", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR ) },
72
0
        { "error-bars-y-positive", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_POSITIVE ) },
73
0
        { "error-bars-y-negative", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_NEGATIVE ) },
74
0
        { "label",        ::chart::SchResId( STR_DATA_ROLE_LABEL ) },
75
0
        { "values-first", ::chart::SchResId( STR_DATA_ROLE_FIRST ) },
76
0
        { "values-last",  ::chart::SchResId( STR_DATA_ROLE_LAST ) },
77
0
        { "values-max",   ::chart::SchResId( STR_DATA_ROLE_MAX ) },
78
0
        { "values-min",   ::chart::SchResId( STR_DATA_ROLE_MIN ) },
79
0
        { "values-x",     ::chart::SchResId( STR_DATA_ROLE_X ) },
80
0
        { "values-y",     ::chart::SchResId( STR_DATA_ROLE_Y ) },
81
0
        { "values-size",  ::chart::SchResId( STR_DATA_ROLE_SIZE ) },
82
0
        { "values-feature", ::chart::SchResId( STR_DATA_ROLE_FEATURE ) },
83
0
        { "FillColor",    ::chart::SchResId( STR_PROPERTY_ROLE_FILLCOLOR ) },
84
0
        { "BorderColor",  ::chart::SchResId( STR_PROPERTY_ROLE_BORDERCOLOR ) },
85
0
    };
86
87
0
    tTranslationMap::const_iterator aIt( aTranslationMap.find( rRoleString ));
88
0
    if( aIt != aTranslationMap.end())
89
0
    {
90
0
        aResult = (*aIt).second;
91
0
    }
92
0
    return aResult;
93
0
}
94
95
typedef std::map< OUString, sal_Int32 > lcl_tRoleIndexMap;
96
97
lcl_tRoleIndexMap lcl_createRoleIndexMap()
98
0
{
99
0
    lcl_tRoleIndexMap aMap;
100
0
    sal_Int32 nIndex = 0;
101
102
0
    aMap[ u"label"_ustr ] =                 ++nIndex;
103
0
    aMap[ u"categories"_ustr ] =            ++nIndex;
104
0
    aMap[ u"values-x"_ustr ] =              ++nIndex;
105
0
    aMap[ u"values-y"_ustr ] =              ++nIndex;
106
0
    aMap[ u"error-bars-x"_ustr ] =          ++nIndex;
107
0
    aMap[ u"error-bars-x-positive"_ustr ] = ++nIndex;
108
0
    aMap[ u"error-bars-x-negative"_ustr ] = ++nIndex;
109
0
    aMap[ u"error-bars-y"_ustr ] =          ++nIndex;
110
0
    aMap[ u"error-bars-y-positive"_ustr ] = ++nIndex;
111
0
    aMap[ u"error-bars-y-negative"_ustr ] = ++nIndex;
112
0
    aMap[ u"values-first"_ustr ] =          ++nIndex;
113
0
    aMap[ u"values-min"_ustr ] =            ++nIndex;
114
0
    aMap[ u"values-max"_ustr ] =            ++nIndex;
115
0
    aMap[ u"values-last"_ustr ] =           ++nIndex;
116
0
    aMap[ u"values-size"_ustr ] =           ++nIndex;
117
0
    aMap[ u"values-feature"_ustr ] =        ++nIndex;
118
119
0
    return aMap;
120
0
}
121
122
123
struct lcl_RolesWithRangeAppend
124
{
125
    typedef Reference< data::XLabeledDataSequence > value_type;
126
    typedef ::chart::DialogModel::tRolesWithRanges tContainerType;
127
128
    explicit lcl_RolesWithRangeAppend( tContainerType * rCnt,
129
                                       OUString aLabelRole )
130
0
            : m_rDestCnt( rCnt ),
131
0
              m_aRoleForLabelSeq(std::move( aLabelRole ))
132
0
    {}
133
134
    lcl_RolesWithRangeAppend & operator= ( const value_type & xVal )
135
0
    {
136
0
        try
137
0
        {
138
0
            if( xVal.is())
139
0
            {
140
                // data sequence
141
0
                Reference< data::XDataSequence > xSeq( xVal->getValues());
142
0
                if( xSeq.is())
143
0
                {
144
0
                    OUString aRole;
145
0
                    Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
146
0
                    if( xProp->getPropertyValue( u"Role"_ustr ) >>= aRole )
147
0
                    {
148
0
                        m_rDestCnt->emplace(aRole, xSeq->getSourceRangeRepresentation());
149
                        // label
150
0
                        if( aRole == m_aRoleForLabelSeq )
151
0
                        {
152
0
                            Reference< data::XDataSequence > xLabelSeq( xVal->getLabel());
153
0
                            if( xLabelSeq.is())
154
0
                            {
155
0
                                m_rDestCnt->emplace(
156
0
                                        lcl_aLabelRole, xLabelSeq->getSourceRangeRepresentation());
157
0
                            }
158
0
                        }
159
0
                    }
160
0
                }
161
0
            }
162
0
        }
163
0
        catch( const uno::Exception & )
164
0
        {
165
0
            DBG_UNHANDLED_EXCEPTION("chart2");
166
0
        }
167
0
        return *this;
168
0
    }
169
170
    // Implement output operator requirements as required by std::copy (and
171
    // implement prefix increment in terms of postfix increment to avoid unused
172
    // member function warnings for the latter in the common case where
173
    // std::copy would not actually need it):
174
0
    lcl_RolesWithRangeAppend & operator* ()     { return *this; }
175
0
    lcl_RolesWithRangeAppend & operator++ ()    { return operator++(0); }
176
0
    lcl_RolesWithRangeAppend & operator++ (int) { return *this; }
177
178
private:
179
    tContainerType * m_rDestCnt;
180
    OUString m_aRoleForLabelSeq;
181
};
182
183
}
184
185
namespace std
186
{
187
    template<> struct iterator_traits<lcl_RolesWithRangeAppend>
188
    {
189
        typedef std::output_iterator_tag iterator_category;
190
        typedef Reference< data::XLabeledDataSequence > value_type;
191
        typedef value_type& reference;
192
    };
193
}
194
195
namespace {
196
197
void lcl_SetSequenceRole(
198
    const Reference< data::XDataSequence > & xSeq,
199
    const OUString & rRole )
200
0
{
201
0
    Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY );
202
0
    if( xProp.is())
203
0
        xProp->setPropertyValue( u"Role"_ustr , uno::Any( rRole ));
204
0
}
205
206
Sequence< OUString > lcl_CopyExcludingValuesFirst(
207
    Sequence< OUString > const & i_aInput )
208
0
{
209
0
    Sequence< OUString > aOutput( i_aInput.getLength());
210
0
    auto pOutput = aOutput.getArray();
211
0
    int nSourceIndex, nDestIndex;
212
0
    for( nSourceIndex = nDestIndex = 0; nSourceIndex < i_aInput.getLength(); nSourceIndex++ )
213
0
    {
214
0
        if( i_aInput[nSourceIndex] == "values-first" )
215
0
        {
216
0
            aOutput.realloc( aOutput.getLength() - 1 );
217
0
            pOutput = aOutput.getArray();
218
0
        }
219
0
        else
220
0
        {
221
0
            pOutput[nDestIndex] = i_aInput[nSourceIndex];
222
0
            nDestIndex++;
223
0
        }
224
0
    }
225
0
    return aOutput;
226
0
}
227
228
rtl::Reference< ::chart::DataSeries > lcl_CreateNewSeries(
229
    const rtl::Reference< ::chart::ChartType > & xChartType,
230
    sal_Int32 nNewSeriesIndex,
231
    sal_Int32 nTotalNumberOfSeriesInCTGroup,
232
    const rtl::Reference< ::chart::Diagram > & xDiagram,
233
    const rtl::Reference< ::chart::ChartTypeTemplate > & xTemplate,
234
    bool bCreateDataCachedSequences )
235
0
{
236
    // create plain series
237
0
    rtl::Reference< ::chart::DataSeries > xResult = new ::chart::DataSeries();
238
0
    if( xTemplate.is())
239
0
    {
240
        // @deprecated: correct default color should be found by view
241
        // without setting it as hard attribute
242
0
        Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
243
0
        if( xColorScheme.is())
244
0
            xResult->setPropertyValue( u"Color"_ustr , uno::Any( xColorScheme->getColorByIndex( nNewSeriesIndex )));
245
0
        std::size_t nGroupIndex=0;
246
0
        if( xChartType.is())
247
0
        {
248
0
            std::vector< rtl::Reference< ::chart::ChartType > > aCTs =
249
0
                xDiagram->getChartTypes();
250
0
            for( ; nGroupIndex < aCTs.size(); ++nGroupIndex)
251
0
                if( aCTs[nGroupIndex] == xChartType )
252
0
                    break;
253
0
            if( nGroupIndex == aCTs.size())
254
0
                nGroupIndex = 0;
255
0
        }
256
0
        xTemplate->applyStyle2( xResult, nGroupIndex, nNewSeriesIndex, nTotalNumberOfSeriesInCTGroup );
257
0
    }
258
259
0
    if( bCreateDataCachedSequences )
260
0
    {
261
        // set chart type specific roles
262
0
        if( xChartType.is() )
263
0
        {
264
0
            std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences;
265
0
            const OUString aRoleOfSeqForSeriesLabel = xChartType->getRoleOfSequenceForSeriesLabel();
266
0
            const OUString aLabel(::chart::SchResId(STR_DATA_UNNAMED_SERIES));
267
0
            Sequence< OUString > aPossibleRoles( xChartType->getSupportedMandatoryRoles());
268
0
            Sequence< OUString > aPossibleOptRoles( xChartType->getSupportedOptionalRoles());
269
270
            //special handling for candlestick type
271
0
            if( xTemplate.is())
272
0
            {
273
0
                rtl::Reference< ::chart::DataInterpreter > xInterpreter( xTemplate->getDataInterpreter2());
274
0
                if( xInterpreter.is())
275
0
                {
276
0
                    sal_Int32 nStockVariant;
277
0
                    if( xInterpreter->getChartTypeSpecificData(u"stock variant"_ustr) >>= nStockVariant )
278
0
                    {
279
0
                        if( nStockVariant == 0 || nStockVariant == 2) {
280
                            //delete "values-first" role
281
0
                            aPossibleRoles = lcl_CopyExcludingValuesFirst(aPossibleRoles);
282
0
                            aPossibleOptRoles = lcl_CopyExcludingValuesFirst(aPossibleOptRoles);
283
0
                        }
284
0
                    }
285
0
                }
286
0
            }
287
288
0
            const Sequence< OUString > aRoles( aPossibleRoles );
289
0
            const Sequence< OUString > aOptRoles( aPossibleOptRoles );
290
291
0
            for(OUString const & role : aRoles)
292
0
            {
293
0
                if( role == lcl_aLabelRole )
294
0
                    continue;
295
0
                Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence() );
296
0
                lcl_SetSequenceRole( xSeq, role );
297
                // assert that aRoleOfSeqForSeriesLabel is part of the mandatory roles
298
0
                if( role == aRoleOfSeqForSeriesLabel )
299
0
                {
300
0
                    Reference< data::XDataSequence > xLabel( ::chart::DataSourceHelper::createCachedDataSequence( aLabel ));
301
0
                    lcl_SetSequenceRole( xLabel, lcl_aLabelRole );
302
0
                    aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq, xLabel ));
303
0
                }
304
0
                else
305
0
                    aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq ));
306
0
            }
307
308
0
            for(OUString const & role : aOptRoles)
309
0
            {
310
0
                if( role == lcl_aLabelRole )
311
0
                    continue;
312
0
                Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence());
313
0
                lcl_SetSequenceRole( xSeq, role );
314
0
                aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq ));
315
0
            }
316
317
0
            xResult->setData( aNewSequences );
318
0
        }
319
0
    }
320
321
0
    return xResult;
322
0
}
323
324
struct lcl_addSeriesNumber
325
{
326
    sal_Int32 operator() ( sal_Int32 nCurrentNumber, const Reference< XDataSeriesContainer > & xCnt ) const
327
0
    {
328
0
        if( xCnt.is())
329
0
            return nCurrentNumber + (xCnt->getDataSeries().getLength());
330
0
        return nCurrentNumber;
331
0
    }
332
};
333
334
} // anonymous namespace
335
336
namespace chart
337
{
338
339
DialogModelTimeBasedInfo::DialogModelTimeBasedInfo():
340
0
    bTimeBased(false),
341
0
    nStart(0),
342
0
    nEnd(0)
343
0
{
344
0
}
345
346
DialogModel::DialogModel(
347
    rtl::Reference<::chart::ChartModel> xChartDocument ) :
348
0
        m_xChartDocument(std::move( xChartDocument )),
349
0
        m_aTimerTriggeredControllerLock( m_xChartDocument )
350
0
{
351
0
}
352
353
DialogModel::~DialogModel()
354
0
{
355
0
    if(maTimeBasedInfo.bTimeBased)
356
0
    {
357
0
        getModel().setTimeBasedRange(maTimeBasedInfo.nStart, maTimeBasedInfo.nEnd);
358
0
    }
359
0
}
360
361
void DialogModel::setTemplate(
362
    const rtl::Reference< ChartTypeTemplate > & xTemplate )
363
0
{
364
0
    m_xTemplate = xTemplate;
365
0
}
366
367
std::shared_ptr< RangeSelectionHelper > const &
368
    DialogModel::getRangeSelectionHelper() const
369
0
{
370
0
    if( ! m_spRangeSelectionHelper)
371
0
        m_spRangeSelectionHelper =
372
0
            std::make_shared<RangeSelectionHelper>( m_xChartDocument );
373
374
0
    return m_spRangeSelectionHelper;
375
0
}
376
377
const rtl::Reference<::chart::ChartModel> & DialogModel::getChartModel() const
378
0
{
379
0
    return m_xChartDocument;
380
0
}
381
382
Reference< data::XDataProvider > DialogModel::getDataProvider() const
383
0
{
384
0
    Reference< data::XDataProvider > xResult;
385
0
    if( m_xChartDocument.is())
386
0
        xResult.set( m_xChartDocument->getDataProvider());
387
0
    return xResult;
388
0
}
389
390
std::vector< rtl::Reference< ChartType > >
391
    DialogModel::getAllDataSeriesContainers() const
392
0
{
393
0
    std::vector< rtl::Reference< ChartType > > aResult;
394
395
0
    try
396
0
    {
397
0
        if( !m_xChartDocument )
398
0
            return {};
399
0
        rtl::Reference< Diagram > xDiagram = m_xChartDocument->getFirstChartDiagram();
400
0
        if( xDiagram.is())
401
0
        {
402
0
            const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq(
403
0
                xDiagram->getBaseCoordinateSystems());
404
0
            for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq )
405
0
            {
406
0
                aResult.insert(aResult.end(),
407
0
                               coords->getChartTypes2().begin(),
408
0
                               coords->getChartTypes2().end());
409
410
0
            }
411
0
        }
412
0
    }
413
0
    catch( const uno::Exception & )
414
0
    {
415
0
        DBG_UNHANDLED_EXCEPTION("chart2");
416
0
    }
417
418
0
    return aResult;
419
0
}
420
421
std::vector< DialogModel::tSeriesWithChartTypeByName >
422
    DialogModel::getAllDataSeriesWithLabel() const
423
0
{
424
0
    std::vector< tSeriesWithChartTypeByName > aResult;
425
0
    std::vector< rtl::Reference< ChartType > > aContainers(
426
0
        getAllDataSeriesContainers());
427
428
0
    for (const auto & rxChartType : aContainers )
429
0
    {
430
0
        try
431
0
        {
432
0
            const std::vector< rtl::Reference< DataSeries > > & aSeq = rxChartType->getDataSeries2();
433
0
            OUString aRole = rxChartType->getRoleOfSequenceForSeriesLabel();
434
0
            for( rtl::Reference< DataSeries > const & dataSeries : aSeq )
435
0
            {
436
0
                aResult.push_back(
437
0
                    ::chart::DialogModel::tSeriesWithChartTypeByName(
438
0
                        dataSeries->getLabelForRole( aRole ),
439
0
                        std::make_pair( dataSeries, rxChartType )));
440
0
            }
441
0
        }
442
0
        catch( const uno::Exception & )
443
0
        {
444
0
            DBG_UNHANDLED_EXCEPTION("chart2");
445
0
        }
446
0
    }
447
448
0
    return aResult;
449
0
}
450
451
namespace {
452
453
void addMissingRoles(DialogModel::tRolesWithRanges& rResult, const uno::Sequence<OUString>& rRoles)
454
0
{
455
0
    for(OUString const & role : rRoles)
456
0
    {
457
0
        if(rResult.find(role) == rResult.end())
458
0
            rResult.emplace(role, OUString());
459
0
    }
460
0
}
461
462
/**
463
 * Insert a new data series to chart type at position after specified series
464
 * position.
465
 *
466
 * @param xChartType chart type that contains data series.
467
 * @param xSeries insertion position.  The new series will be inserted after
468
 *                this one.
469
 * @param xNewSeries new data series to insert.
470
 */
471
void addNewSeriesToContainer(
472
    const rtl::Reference<ChartType>& xChartType,
473
    const rtl::Reference<DataSeries>& xSeries,
474
    const rtl::Reference<DataSeries>& xNewSeries )
475
0
{
476
0
    auto aSeries = xChartType->getDataSeries2();
477
478
0
    auto aIt = std::find( aSeries.begin(), aSeries.end(), xSeries);
479
480
0
    if( aIt == aSeries.end())
481
        // if we have no series we insert at the first position.
482
0
        aIt = aSeries.begin();
483
0
    else
484
        // vector::insert inserts before, so we have to advance
485
0
        ++aIt;
486
487
0
    aSeries.insert(aIt, xNewSeries);
488
0
    xChartType->setDataSeries(aSeries);
489
0
}
490
491
}
492
493
DialogModel::tRolesWithRanges DialogModel::getRolesWithRanges(
494
    const Reference< XDataSeries > & xSeries,
495
    const OUString & aRoleOfSequenceForLabel,
496
    const rtl::Reference< ::chart::ChartType > & xChartType )
497
0
{
498
0
    DialogModel::tRolesWithRanges aResult;
499
0
    try
500
0
    {
501
0
        Reference< data::XDataSource > xSource( xSeries, uno::UNO_QUERY_THROW );
502
0
        const Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSource->getDataSequences());
503
0
        std::copy( aSeq.begin(), aSeq.end(),
504
0
                     lcl_RolesWithRangeAppend( &aResult, aRoleOfSequenceForLabel ));
505
0
        if( xChartType.is())
506
0
        {
507
            // add missing mandatory roles
508
0
            Sequence< OUString > aRoles( xChartType->getSupportedMandatoryRoles());
509
0
            addMissingRoles(aResult, aRoles);
510
511
            // add missing optional roles
512
0
            aRoles = xChartType->getSupportedOptionalRoles();
513
0
            addMissingRoles(aResult, aRoles);
514
515
            // add missing property roles
516
0
            aRoles = xChartType->getSupportedPropertyRoles();
517
0
            addMissingRoles(aResult, aRoles);
518
0
        }
519
0
    }
520
0
    catch( const uno::Exception & )
521
0
    {
522
0
        DBG_UNHANDLED_EXCEPTION("chart2");
523
0
    }
524
0
    return aResult;
525
0
}
526
527
void DialogModel::moveSeries(
528
    const rtl::Reference< DataSeries > & xSeries,
529
    MoveDirection eDirection )
530
0
{
531
0
    m_aTimerTriggeredControllerLock.startTimer();
532
0
    ControllerLockGuardUNO aLockedControllers( m_xChartDocument );
533
534
0
    rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram());
535
0
    xDiagram->moveSeries( xSeries, eDirection==MoveDirection::Down );
536
0
}
537
538
rtl::Reference< ::chart::DataSeries > DialogModel::insertSeriesAfter(
539
    const Reference< XDataSeries > & xUnoSeries,
540
    const rtl::Reference< ::chart::ChartType > & xChartType,
541
    bool bCreateDataCachedSequences /* = false */ )
542
0
{
543
0
    m_aTimerTriggeredControllerLock.startTimer();
544
0
    ControllerLockGuardUNO aLockedControllers( m_xChartDocument );
545
0
    rtl::Reference< ::chart::DataSeries > xNewSeries;
546
0
    rtl::Reference<DataSeries> xSeries = dynamic_cast<DataSeries*>(xUnoSeries.get());
547
0
    assert(xSeries || !xUnoSeries);
548
549
0
    try
550
0
    {
551
0
        rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram() );
552
0
        ThreeDLookScheme e3DScheme = xDiagram->detectScheme();
553
554
0
        sal_Int32 nSeriesInChartType = 0;
555
0
        const sal_Int32 nTotalSeries = countSeries();
556
0
        if( xChartType.is())
557
0
        {
558
0
            nSeriesInChartType = xChartType->getDataSeries().getLength();
559
0
        }
560
561
        // create new series
562
0
        xNewSeries =
563
0
            lcl_CreateNewSeries(
564
0
                xChartType,
565
0
                nTotalSeries, // new series' index
566
0
                nSeriesInChartType,
567
0
                xDiagram,
568
0
                m_xTemplate,
569
0
                bCreateDataCachedSequences );
570
571
        // add new series to container
572
0
        if( xNewSeries.is())
573
0
            addNewSeriesToContainer(xChartType, xSeries, xNewSeries);
574
575
0
        xDiagram->setScheme( e3DScheme );
576
0
    }
577
0
    catch( const uno::Exception & )
578
0
    {
579
0
        DBG_UNHANDLED_EXCEPTION("chart2");
580
0
    }
581
0
    return xNewSeries;
582
0
}
583
584
void DialogModel::deleteSeries(
585
    const rtl::Reference< DataSeries > & xSeries,
586
    const rtl::Reference< ChartType > & xChartType )
587
0
{
588
0
    m_aTimerTriggeredControllerLock.startTimer();
589
0
    ControllerLockGuardUNO aLockedControllers( m_xChartDocument );
590
591
0
    xChartType->deleteSeries( xSeries );
592
0
}
593
594
uno::Reference< chart2::data::XLabeledDataSequence > DialogModel::getCategories() const
595
0
{
596
0
    uno::Reference< chart2::data::XLabeledDataSequence > xResult;
597
0
    try
598
0
    {
599
0
        if( m_xChartDocument.is())
600
0
        {
601
0
            rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram());
602
0
            if (xDiagram.is())
603
0
                xResult = xDiagram->getCategories();
604
0
        }
605
0
    }
606
0
    catch( const uno::Exception & )
607
0
    {
608
0
        DBG_UNHANDLED_EXCEPTION("chart2");
609
0
    }
610
0
    return xResult;
611
0
}
612
613
void DialogModel::setCategories( const Reference< chart2::data::XLabeledDataSequence > & xCategories )
614
0
{
615
0
    if( !m_xChartDocument.is())
616
0
        return;
617
618
0
    rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram());
619
0
    if( !xDiagram.is())
620
0
        return;
621
622
    // categories
623
0
    bool bSupportsCategories = true;
624
625
0
    rtl::Reference< ChartType > xFirstChartType( xDiagram->getChartTypeByIndex( 0 ) );
626
0
    if( xFirstChartType.is() )
627
0
    {
628
0
        sal_Int32 nAxisType = xFirstChartType->getAxisType(0); // x-axis
629
0
        bSupportsCategories = (nAxisType == AxisType::CATEGORY);
630
0
    }
631
0
    xDiagram->setCategories( xCategories, true, bSupportsCategories );
632
0
}
633
634
OUString DialogModel::getCategoriesRange() const
635
0
{
636
0
    OUString aRange;
637
0
    try
638
0
    {
639
0
        uno::Reference< chart2::data::XLabeledDataSequence > xLSeq( getCategories());
640
0
        if( xLSeq.is())
641
0
        {
642
0
            Reference< data::XDataSequence > xSeq( xLSeq->getValues());
643
0
            if( xSeq.is())
644
0
                aRange = xSeq->getSourceRangeRepresentation();
645
0
        }
646
0
    }
647
0
    catch (const lang::DisposedException&)
648
0
    {
649
0
        TOOLS_WARN_EXCEPTION( "chart2", "unexpected exception caught" );
650
0
    }
651
0
    return aRange;
652
0
}
653
654
bool DialogModel::isCategoryDiagram() const
655
0
{
656
0
    bool bRet = false;
657
0
    if( m_xChartDocument.is() && m_xChartDocument->getFirstChartDiagram())
658
0
        bRet = m_xChartDocument->getFirstChartDiagram()->isCategory();
659
0
    return bRet;
660
0
}
661
662
void DialogModel::detectArguments(
663
    OUString & rOutRangeString,
664
    bool & rOutUseColumns,
665
    bool & rOutFirstCellAsLabel,
666
    bool & rOutHasCategories ) const
667
0
{
668
0
    try
669
0
    {
670
0
        uno::Sequence< sal_Int32 > aSequenceMapping;//todo YYYX
671
672
        // Note: unused data is currently not supported in being passed to detectRangeSegmentation
673
0
        if( m_xChartDocument.is())
674
0
        {
675
0
            (void)DataSourceHelper::detectRangeSegmentation(
676
0
                m_xChartDocument,
677
0
                rOutRangeString, aSequenceMapping, rOutUseColumns, rOutFirstCellAsLabel, rOutHasCategories );
678
0
        }
679
0
    }
680
0
    catch( const uno::Exception & )
681
0
    {
682
0
        DBG_UNHANDLED_EXCEPTION("chart2");
683
0
    }
684
0
}
685
686
bool DialogModel::allArgumentsForRectRangeDetected() const
687
0
{
688
0
    return DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument );
689
0
}
690
691
void DialogModel::startControllerLockTimer()
692
0
{
693
0
    m_aTimerTriggeredControllerLock.startTimer();
694
0
}
695
696
void DialogModel::setData(
697
    const Sequence< beans::PropertyValue > & rArguments )
698
0
{
699
0
    m_aTimerTriggeredControllerLock.startTimer();
700
0
    ControllerLockGuardUNO aLockedControllers( m_xChartDocument );
701
702
0
    Reference< data::XDataProvider > xDataProvider( getDataProvider());
703
0
    if( ! xDataProvider.is() ||
704
0
        ! m_xTemplate.is() )
705
0
    {
706
0
        OSL_FAIL( "Model objects missing" );
707
0
        return;
708
0
    }
709
710
0
    try
711
0
    {
712
0
        Reference< chart2::data::XDataSource > xDataSource(
713
0
            xDataProvider->createDataSource( rArguments ) );
714
715
0
        rtl::Reference< ::chart::DataInterpreter > xInterpreter(
716
0
            m_xTemplate->getDataInterpreter2());
717
0
        if( xInterpreter.is())
718
0
        {
719
0
            rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram() );
720
0
            ThreeDLookScheme e3DScheme = xDiagram->detectScheme();
721
722
0
            std::vector< rtl::Reference< DataSeries > > aSeriesToReUse =
723
0
                xDiagram->getDataSeries();
724
0
            applyInterpretedData(
725
0
                xInterpreter->interpretDataSource(
726
0
                    xDataSource, rArguments,
727
0
                    aSeriesToReUse ),
728
0
                aSeriesToReUse);
729
730
0
            xDiagram->setScheme( e3DScheme );
731
0
        }
732
0
    }
733
0
    catch( const uno::Exception & )
734
0
    {
735
0
        DBG_UNHANDLED_EXCEPTION("chart2");
736
0
    }
737
0
}
738
739
void DialogModel::setTimeBasedRange( bool bTimeBased, sal_Int32 nStart, sal_Int32 nEnd) const
740
0
{
741
0
    maTimeBasedInfo.nStart = nStart;
742
0
    maTimeBasedInfo.nEnd = nEnd;
743
0
    maTimeBasedInfo.bTimeBased = bTimeBased;
744
0
}
745
746
OUString DialogModel::ConvertRoleFromInternalToUI( const OUString & rRoleString )
747
0
{
748
0
    return lcl_ConvertRole( rRoleString );
749
0
}
750
751
OUString DialogModel::GetRoleDataLabel()
752
0
{
753
0
    return ::chart::SchResId(STR_OBJECT_DATALABELS);
754
0
}
755
756
sal_Int32 DialogModel::GetRoleIndexForSorting( const OUString & rInternalRoleString )
757
0
{
758
0
    static lcl_tRoleIndexMap aRoleIndexMap = lcl_createRoleIndexMap();
759
760
0
    lcl_tRoleIndexMap::const_iterator aIt( aRoleIndexMap.find( rInternalRoleString ));
761
0
    if( aIt != aRoleIndexMap.end())
762
0
        return aIt->second;
763
764
0
    return 0;
765
0
}
766
767
// private methods
768
769
void DialogModel::applyInterpretedData(
770
    const InterpretedData & rNewData,
771
    const std::vector< rtl::Reference< DataSeries > > & rSeriesToReUse )
772
0
{
773
0
    if( ! m_xChartDocument.is())
774
0
        return;
775
776
0
    m_aTimerTriggeredControllerLock.startTimer();
777
0
    rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram());
778
0
    if( !xDiagram.is())
779
0
        return;
780
781
    // styles
782
0
    if( m_xTemplate.is() )
783
0
    {
784
0
        sal_Int32 nGroup = 0;
785
0
        sal_Int32 nSeriesCounter = 0;
786
0
        sal_Int32 nNewSeriesIndex = static_cast< sal_Int32 >( rSeriesToReUse.size());
787
0
        const sal_Int32 nOuterSize=rNewData.Series.size();
788
789
0
        for(; nGroup < nOuterSize; ++nGroup)
790
0
        {
791
0
            const std::vector< rtl::Reference< DataSeries > > & aSeries( rNewData.Series[ nGroup ] );
792
0
            const sal_Int32 nSeriesInGroup = aSeries.size();
793
0
            for( sal_Int32 nSeries=0; nSeries<nSeriesInGroup; ++nSeries, ++nSeriesCounter )
794
0
            {
795
0
                if( std::find( rSeriesToReUse.begin(), rSeriesToReUse.end(), aSeries[nSeries] )
796
0
                    == rSeriesToReUse.end())
797
0
                {
798
0
                    if( aSeries[nSeries].is())
799
0
                    {
800
                        // @deprecated: correct default color should be found by view
801
                        // without setting it as hard attribute
802
0
                        Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
803
0
                        if( xColorScheme.is())
804
0
                            aSeries[nSeries]->setPropertyValue( u"Color"_ustr ,
805
0
                                uno::Any( xColorScheme->getColorByIndex( nSeriesCounter )));
806
0
                    }
807
0
                    m_xTemplate->applyStyle2( aSeries[nSeries], nGroup, nNewSeriesIndex++, nSeriesInGroup );
808
0
                }
809
0
            }
810
0
        }
811
0
    }
812
813
    // data series
814
0
    std::vector< rtl::Reference< ChartType > > aSeriesCnt = getAllDataSeriesContainers();
815
816
0
    OSL_ASSERT( aSeriesCnt.size() == rNewData.Series.size());
817
818
0
    auto aSrcIt = rNewData.Series.begin();
819
0
    auto aDestIt = aSeriesCnt.begin();
820
0
    for(; aSrcIt != rNewData.Series.end() && aDestIt != aSeriesCnt.end();
821
0
        ++aSrcIt, ++aDestIt )
822
0
    {
823
0
        try
824
0
        {
825
0
            OSL_ASSERT( (*aDestIt).is());
826
0
            (*aDestIt)->setDataSeries( *aSrcIt );
827
0
        }
828
0
        catch( const uno::Exception & )
829
0
        {
830
0
            DBG_UNHANDLED_EXCEPTION("chart2");
831
0
        }
832
0
    }
833
834
0
    DialogModel::setCategories(rNewData.Categories);
835
0
}
836
837
sal_Int32 DialogModel::countSeries() const
838
0
{
839
0
    std::vector< rtl::Reference< ChartType > > aCnt( getAllDataSeriesContainers());
840
0
    return std::accumulate( aCnt.begin(), aCnt.end(), 0, lcl_addSeriesNumber());
841
0
}
842
843
ChartModel& DialogModel::getModel() const
844
0
{
845
0
    return *m_xChartDocument;
846
0
}
847
848
} //  namespace chart
849
850
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */