Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/chart2/source/tools/DiagramHelper.cxx
Line
Count
Source (jump to first uncovered line)
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 <DiagramHelper.hxx>
21
#include <Diagram.hxx>
22
#include <DataSeries.hxx>
23
#include <DataSeriesHelper.hxx>
24
#include <Axis.hxx>
25
#include <AxisHelper.hxx>
26
#include <ChartType.hxx>
27
#include <ChartModel.hxx>
28
#include <ExplicitCategoriesProvider.hxx>
29
#include <RelativePositionHelper.hxx>
30
#include <ControllerLockGuard.hxx>
31
#include <NumberFormatterWrapper.hxx>
32
#include <unonames.hxx>
33
#include <BaseCoordinateSystem.hxx>
34
35
#include <com/sun/star/chart/XDiagramPositioning.hpp>
36
#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
37
#include <com/sun/star/chart2/AxisType.hpp>
38
#include <com/sun/star/chart2/RelativePosition.hpp>
39
#include <com/sun/star/chart2/RelativeSize.hpp>
40
#include <com/sun/star/chart2/StackingDirection.hpp>
41
42
#include <com/sun/star/util/NumberFormat.hpp>
43
44
#include <unotools/saveopt.hxx>
45
#include <svl/numformat.hxx>
46
#include <svl/zforlist.hxx>
47
#include <svl/zformat.hxx>
48
#include <vcl/svapp.hxx>
49
#include <vcl/settings.hxx>
50
#include <comphelper/sequence.hxx>
51
#include <comphelper/diagnose_ex.hxx>
52
#include <sal/log.hxx>
53
54
#include <limits>
55
56
using namespace ::com::sun::star;
57
using namespace ::com::sun::star::chart2;
58
59
using ::com::sun::star::uno::Reference;
60
using ::com::sun::star::uno::Sequence;
61
using ::com::sun::star::uno::Any;
62
using ::com::sun::star::chart2::XAnyDescriptionAccess;
63
64
namespace chart
65
{
66
67
StackMode DiagramHelper::getStackModeFromChartType(
68
    const rtl::Reference< ChartType > & xChartType,
69
    bool& rbFound, bool& rbAmbiguous,
70
    const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem )
71
0
{
72
0
    StackMode eStackMode = StackMode::NONE;
73
0
    rbFound = false;
74
0
    rbAmbiguous = false;
75
76
0
    try
77
0
    {
78
0
        const std::vector< rtl::Reference< DataSeries > > & aSeries = xChartType->getDataSeries2();
79
80
0
        chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING;
81
0
        bool bDirectionInitialized = false;
82
83
        // first series is irrelevant for stacking, start with second, unless
84
        // there is only one series
85
0
        const sal_Int32 nSeriesCount = aSeries.size();
86
0
        sal_Int32 i = (nSeriesCount == 1) ? 0: 1;
87
0
        for( ; i<nSeriesCount; ++i )
88
0
        {
89
0
            rbFound = true;
90
0
            chart2::StackingDirection eCurrentDirection = eCommonDirection;
91
            // property is not MAYBEVOID
92
0
            bool bSuccess = ( aSeries[i]->getPropertyValue( u"StackingDirection"_ustr ) >>= eCurrentDirection );
93
0
            OSL_ASSERT( bSuccess );
94
0
            if( ! bDirectionInitialized )
95
0
            {
96
0
                eCommonDirection = eCurrentDirection;
97
0
                bDirectionInitialized = true;
98
0
            }
99
0
            else
100
0
            {
101
0
                if( eCommonDirection != eCurrentDirection )
102
0
                {
103
0
                    rbAmbiguous = true;
104
0
                    break;
105
0
                }
106
0
            }
107
0
        }
108
109
0
        if( rbFound )
110
0
        {
111
0
            if( eCommonDirection == chart2::StackingDirection_Z_STACKING )
112
0
                eStackMode = StackMode::ZStacked;
113
0
            else if( eCommonDirection == chart2::StackingDirection_Y_STACKING )
114
0
            {
115
0
                eStackMode = StackMode::YStacked;
116
117
                // percent stacking
118
0
                if( xCorrespondingCoordinateSystem.is() )
119
0
                {
120
0
                    if( 1 < xCorrespondingCoordinateSystem->getDimension() )
121
0
                    {
122
0
                        sal_Int32 nAxisIndex = 0;
123
0
                        if( nSeriesCount )
124
0
                            nAxisIndex = aSeries[0]->getAttachedAxisIndex();
125
126
0
                        rtl::Reference< Axis > xAxis =
127
0
                            xCorrespondingCoordinateSystem->getAxisByDimension2( 1,nAxisIndex );
128
0
                        if( xAxis.is())
129
0
                        {
130
0
                            chart2::ScaleData aScaleData = xAxis->getScaleData();
131
0
                            if( aScaleData.AxisType==chart2::AxisType::PERCENT )
132
0
                                eStackMode = StackMode::YStackedPercent;
133
0
                        }
134
0
                    }
135
0
                }
136
0
            }
137
0
        }
138
0
    }
139
0
    catch( const uno::Exception & )
140
0
    {
141
0
        DBG_UNHANDLED_EXCEPTION("chart2");
142
0
    }
143
144
0
    return eStackMode;
145
0
}
146
147
static void lcl_generateAutomaticCategoriesFromChartType(
148
            Sequence< OUString >& rRet,
149
            const rtl::Reference< ChartType >& xChartType )
150
0
{
151
0
    if(!xChartType.is())
152
0
        return;
153
0
    OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() );
154
155
0
    const std::vector< rtl::Reference< DataSeries > > & aSeriesSeq = xChartType->getDataSeries2();
156
0
    for( rtl::Reference< DataSeries > const & dataSeries : aSeriesSeq )
157
0
    {
158
0
        uno::Reference< data::XLabeledDataSequence > xLabeledSeq =
159
0
            ::chart::DataSeriesHelper::getDataSequenceByRole( dataSeries, aMainSeq );
160
0
        if( !xLabeledSeq.is() )
161
0
            continue;
162
0
        Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
163
0
        if( !xValueSeq.is() )
164
0
            continue;
165
0
        rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE );
166
0
        if( rRet.hasElements() )
167
0
            return;
168
0
    }
169
0
}
170
171
Sequence< OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const rtl::Reference< BaseCoordinateSystem > & xCooSys )
172
0
{
173
0
    Sequence< OUString > aRet;
174
175
0
    if( xCooSys.is() )
176
0
    {
177
0
        const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCooSys->getChartTypes2() );
178
0
        for( rtl::Reference< ChartType > const & chartType : aChartTypes )
179
0
        {
180
0
            lcl_generateAutomaticCategoriesFromChartType( aRet, chartType );
181
0
            if( aRet.hasElements() )
182
0
                return aRet;
183
0
        }
184
0
    }
185
0
    return aRet;
186
0
}
187
188
Sequence< OUString > DiagramHelper::getExplicitSimpleCategories(
189
            ChartModel& rModel )
190
0
{
191
0
    rtl::Reference< BaseCoordinateSystem > xCooSys( rModel.getFirstCoordinateSystem() );
192
0
    ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel );
193
0
    return aExplicitCategoriesProvider.getSimpleCategories();
194
0
}
195
196
namespace
197
{
198
void lcl_switchToDateCategories( const rtl::Reference< ChartModel >& xChartDoc, const Reference< XAxis >& xAxis )
199
0
{
200
0
    if( !xAxis.is() )
201
0
        return;
202
0
    if( !xChartDoc.is() )
203
0
        return;
204
205
0
    ScaleData aScale( xAxis->getScaleData() );
206
0
    if( xChartDoc->hasInternalDataProvider() )
207
0
    {
208
        //remove all content the is not of type double and remove multiple level
209
0
        Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY );
210
0
        if( xDataAccess.is() )
211
0
        {
212
0
            Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() );
213
0
            auto aAnyCategoriesRange = asNonConstRange(aAnyCategories);
214
0
            double fTest = 0.0;
215
0
            sal_Int32 nN = aAnyCategories.getLength();
216
0
            for( ; nN--; )
217
0
            {
218
0
                Sequence< Any >& rCat = aAnyCategoriesRange[nN];
219
0
                if( rCat.getLength() > 1 )
220
0
                    rCat.realloc(1);
221
0
                if( rCat.getLength() == 1 )
222
0
                {
223
0
                    Any& rAny = rCat.getArray()[0];
224
0
                    if( !(rAny>>=fTest) )
225
0
                    {
226
0
                        rAny <<= std::numeric_limits<double>::quiet_NaN();
227
0
                    }
228
0
                }
229
0
            }
230
0
            xDataAccess->setAnyRowDescriptions( aAnyCategories );
231
0
        }
232
        //check the numberformat at the axis
233
0
        Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY );
234
0
        if( xAxisProps.is() )
235
0
        {
236
0
            sal_Int32 nNumberFormat = -1;
237
0
            xAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormat;
238
239
0
            Reference< util::XNumberFormats > xNumberFormats( xChartDoc->getNumberFormats() );
240
0
            if( xNumberFormats.is() )
241
0
            {
242
0
                Reference< beans::XPropertySet > xKeyProps;
243
0
                try
244
0
                {
245
0
                    xKeyProps = xNumberFormats->getByKey( nNumberFormat );
246
0
                }
247
0
                catch( const uno::Exception & )
248
0
                {
249
0
                    DBG_UNHANDLED_EXCEPTION("chart2");
250
0
                }
251
0
                sal_Int32 nType = util::NumberFormat::UNDEFINED;
252
0
                if( xKeyProps.is() )
253
0
                    xKeyProps->getPropertyValue( u"Type"_ustr ) >>= nType;
254
0
                if( !( nType & util::NumberFormat::DATE ) )
255
0
                {
256
                    //set a date format to the axis
257
0
                    const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
258
0
                    Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,  rLocaleDataWrapper.getLanguageTag().getLocale(), true/*bCreate*/ );
259
0
                    if( aKeySeq.hasElements() )
260
0
                    {
261
0
                        xAxisProps->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(aKeySeq[0]));
262
0
                    }
263
0
                }
264
0
            }
265
0
        }
266
0
    }
267
0
    if( aScale.AxisType != chart2::AxisType::DATE )
268
0
        AxisHelper::removeExplicitScaling( aScale );
269
0
    aScale.AxisType = chart2::AxisType::DATE;
270
0
    xAxis->setScaleData( aScale );
271
0
}
272
273
void lcl_switchToTextCategories( const rtl::Reference< ChartModel >& xChartDoc, const Reference< XAxis >& xAxis )
274
0
{
275
0
    if( !xAxis.is() )
276
0
        return;
277
0
    if( !xChartDoc.is() )
278
0
        return;
279
0
    ScaleData aScale( xAxis->getScaleData() );
280
0
    if( aScale.AxisType != chart2::AxisType::CATEGORY )
281
0
        AxisHelper::removeExplicitScaling( aScale );
282
    //todo migrate dates to text?
283
0
    aScale.AxisType = chart2::AxisType::CATEGORY;
284
0
    aScale.AutoDateAxis = false;
285
0
    xAxis->setScaleData( aScale );
286
0
}
287
288
}
289
290
void DiagramHelper::switchToDateCategories( const rtl::Reference<::chart::ChartModel>& xChartDoc )
291
0
{
292
0
    if(xChartDoc.is())
293
0
    {
294
0
        ControllerLockGuardUNO aCtrlLockGuard( xChartDoc );
295
296
0
        rtl::Reference< BaseCoordinateSystem > xCooSys = xChartDoc->getFirstCoordinateSystem();
297
0
        if( xCooSys.is() )
298
0
        {
299
0
            rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2(0,0);
300
0
            lcl_switchToDateCategories( xChartDoc, xAxis );
301
0
        }
302
0
    }
303
0
}
304
305
void DiagramHelper::switchToTextCategories( const rtl::Reference<::chart::ChartModel>& xChartDoc )
306
0
{
307
0
    if(xChartDoc.is())
308
0
    {
309
0
        ControllerLockGuardUNO aCtrlLockGuard( xChartDoc );
310
311
0
        rtl::Reference< BaseCoordinateSystem > xCooSys = xChartDoc->getFirstCoordinateSystem();
312
0
        if( xCooSys.is() )
313
0
        {
314
0
            rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2(0,0);
315
0
            lcl_switchToTextCategories( xChartDoc, xAxis );
316
0
        }
317
0
    }
318
0
}
319
320
bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const css::uno::Reference< css::util::XNumberFormats >& xNumberFormats )
321
0
{
322
0
    bool bIsDate = false;
323
0
    if( !xNumberFormats.is() )
324
0
        return bIsDate;
325
326
0
    Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat );
327
0
    if( xKeyProps.is() )
328
0
    {
329
0
        sal_Int32 nType = util::NumberFormat::UNDEFINED;
330
0
        xKeyProps->getPropertyValue( u"Type"_ustr ) >>= nType;
331
0
        bIsDate = nType & util::NumberFormat::DATE;
332
0
    }
333
0
    return bIsDate;
334
0
}
335
336
sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
337
0
{
338
0
    sal_Int32 nRet=-1;
339
340
    //try to get a date format with full year display
341
0
    const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
342
0
    NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
343
0
    SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
344
0
    if( pNumFormatter )
345
0
    {
346
0
        nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, rLanguageTag.getLanguageType() );
347
0
    }
348
0
    else
349
0
    {
350
0
        Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
351
0
        if( xNumberFormats.is() )
352
0
        {
353
0
            Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,
354
0
                    rLanguageTag.getLocale(), true/*bCreate */);
355
0
            if( aKeySeq.hasElements() )
356
0
            {
357
0
                nRet = aKeySeq[0];
358
0
            }
359
0
        }
360
0
    }
361
0
    return nRet;
362
0
}
363
364
sal_Int32 DiagramHelper::getDateTimeInputNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier, double fNumber )
365
0
{
366
0
    sal_Int32 nRet = 0;
367
368
    // Get the most detailed date/time format according to fNumber.
369
0
    NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
370
0
    SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
371
0
    if (!pNumFormatter)
372
0
        SAL_WARN("chart2", "DiagramHelper::getDateTimeInputNumberFormat - no SvNumberFormatter");
373
0
    else
374
0
    {
375
0
        SvNumFormatType nType;
376
        // Obtain best matching date, time or datetime format.
377
0
        nRet = pNumFormatter->GuessDateTimeFormat( nType, fNumber, LANGUAGE_SYSTEM);
378
        // Obtain the corresponding edit format.
379
0
        nRet = pNumFormatter->GetEditFormat( fNumber, nRet, nType, nullptr);
380
0
    }
381
0
    return nRet;
382
0
}
383
384
sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
385
0
{
386
0
    sal_Int32 nRet=-1;
387
0
    const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
388
0
    NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
389
0
    SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
390
0
    if( pNumFormatter )
391
0
    {
392
0
        nRet = pNumFormatter->GetFormatIndex( NF_PERCENT_INT, rLanguageTag.getLanguageType() );
393
0
    }
394
0
    else
395
0
    {
396
0
        Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
397
0
        if( xNumberFormats.is() )
398
0
        {
399
0
            Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT,
400
0
                    rLanguageTag.getLocale(), true/*bCreate*/ );
401
0
            if( aKeySeq.hasElements() )
402
0
            {
403
                // This *assumes* the sequence is sorted as in
404
                // NfIndexTableOffset and the first format is the integer 0%
405
                // format by chance... which usually is the case, but... anyway,
406
                // we usually also have a number formatter so don't reach here.
407
0
                nRet = aKeySeq[0];
408
0
            }
409
0
        }
410
0
    }
411
0
    return nRet;
412
0
}
413
414
bool DiagramHelper::areChartTypesCompatible( const rtl::Reference< ChartType >& xFirstType,
415
                const rtl::Reference< ChartType >& xSecondType )
416
0
{
417
0
    if( !xFirstType.is() || !xSecondType.is() )
418
0
        return false;
419
420
0
    auto aFirstRoles( comphelper::sequenceToContainer<std::vector< OUString >>( xFirstType->getSupportedMandatoryRoles() ) );
421
0
    auto aSecondRoles( comphelper::sequenceToContainer<std::vector< OUString >>( xSecondType->getSupportedMandatoryRoles() ) );
422
0
    std::sort( aFirstRoles.begin(), aFirstRoles.end() );
423
0
    std::sort( aSecondRoles.begin(), aSecondRoles.end() );
424
0
    return ( aFirstRoles == aSecondRoles );
425
0
}
426
427
static void lcl_ensureRange0to1( double& rValue )
428
0
{
429
0
    if(rValue<0.0)
430
0
        rValue=0.0;
431
0
    if(rValue>1.0)
432
0
        rValue=1.0;
433
0
}
434
435
bool DiagramHelper::setDiagramPositioning( const rtl::Reference<::chart::ChartModel>& xChartModel,
436
        const awt::Rectangle& rPosRect /*100th mm*/ )
437
0
{
438
0
    ControllerLockGuardUNO aCtrlLockGuard( xChartModel );
439
440
0
    bool bChanged = false;
441
0
    awt::Size aPageSize( xChartModel->getPageSize() );
442
0
    rtl::Reference< Diagram > xDiagram = xChartModel->getFirstChartDiagram();
443
0
    if( !xDiagram.is() )
444
0
        return bChanged;
445
446
0
    RelativePosition aOldPos;
447
0
    RelativeSize aOldSize;
448
0
    xDiagram->getPropertyValue(u"RelativePosition"_ustr ) >>= aOldPos;
449
0
    xDiagram->getPropertyValue(u"RelativeSize"_ustr ) >>= aOldSize;
450
451
0
    RelativePosition aNewPos;
452
0
    aNewPos.Anchor = drawing::Alignment_TOP_LEFT;
453
0
    aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width);
454
0
    aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height);
455
456
0
    chart2::RelativeSize aNewSize;
457
0
    aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width);
458
0
    aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height);
459
460
0
    lcl_ensureRange0to1( aNewPos.Primary );
461
0
    lcl_ensureRange0to1( aNewPos.Secondary );
462
0
    lcl_ensureRange0to1( aNewSize.Primary );
463
0
    lcl_ensureRange0to1( aNewSize.Secondary );
464
0
    if( (aNewPos.Primary + aNewSize.Primary) > 1.0 )
465
0
        aNewPos.Primary = 1.0 - aNewSize.Primary;
466
0
    if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 )
467
0
        aNewPos.Secondary = 1.0 - aNewSize.Secondary;
468
469
0
    xDiagram->setPropertyValue( u"RelativePosition"_ustr, uno::Any(aNewPos) );
470
0
    xDiagram->setPropertyValue( u"RelativeSize"_ustr, uno::Any(aNewSize) );
471
472
0
    bChanged = (aOldPos.Anchor!=aNewPos.Anchor) ||
473
0
        (aOldPos.Primary!=aNewPos.Primary) ||
474
0
        (aOldPos.Secondary!=aNewPos.Secondary) ||
475
0
        (aOldSize.Primary!=aNewSize.Primary) ||
476
0
        (aOldSize.Secondary!=aNewSize.Secondary);
477
0
    return bChanged;
478
0
}
479
480
awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel )
481
0
{
482
0
    awt::Rectangle aRet(-1,-1,-1,-1);
483
484
0
    rtl::Reference< Diagram > xDiagram = xChartModel->getFirstChartDiagram();
485
0
    if( !xDiagram.is() )
486
0
        return aRet;
487
488
0
    awt::Size aPageSize( xChartModel->getPageSize() );
489
490
0
    RelativePosition aRelPos;
491
0
    RelativeSize aRelSize;
492
0
    xDiagram->getPropertyValue(u"RelativePosition"_ustr ) >>= aRelPos;
493
0
    xDiagram->getPropertyValue(u"RelativeSize"_ustr ) >>= aRelSize;
494
495
0
    awt::Size aAbsSize(
496
0
        static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ),
497
0
        static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height ));
498
499
0
    awt::Point aAbsPos(
500
0
        static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ),
501
0
        static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height ));
502
503
0
    awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor );
504
505
0
    aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height );
506
507
0
    return aRet;
508
0
}
509
510
bool DiagramHelper::switchDiagramPositioningToExcludingPositioning(
511
    ChartModel& rModel, bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning )
512
0
{
513
    //return true if something was changed
514
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(GetODFSaneDefaultVersion());
515
0
    if (SvtSaveOptions::ODFSVER_012 < nCurrentODFVersion)
516
0
    {
517
0
        uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( rModel.getFirstDiagram(), uno::UNO_QUERY );
518
0
        if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() )
519
0
                && !xDiagramPositioning->isExcludingDiagramPositioning() )
520
0
        {
521
0
            ControllerLockGuard aCtrlLockGuard( rModel );
522
0
            bool bModelWasModified = rModel.isModified();
523
0
            xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() );
524
0
            if(bResetModifiedState && !bModelWasModified )
525
0
                rModel.setModified(false);
526
0
            return true;
527
0
        }
528
0
    }
529
0
    return false;
530
0
}
531
532
} //  namespace chart
533
534
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */