Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/tools/TitleHelper.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 <TitleHelper.hxx>
21
#include <Title.hxx>
22
#include <ChartModel.hxx>
23
#include <Axis.hxx>
24
#include <AxisHelper.hxx>
25
#include <Diagram.hxx>
26
#include <ReferenceSizeProvider.hxx>
27
#include <com/sun/star/chart2/FormattedString.hpp>
28
#include <rtl/ustrbuf.hxx>
29
#include <comphelper/diagnose_ex.hxx>
30
#include <sal/log.hxx>
31
32
namespace chart
33
{
34
35
using namespace ::com::sun::star;
36
using namespace ::com::sun::star::chart2;
37
using ::com::sun::star::uno::Reference;
38
39
namespace {
40
41
uno::Reference< XTitled > lcl_getTitleParentFromDiagram(
42
      TitleHelper::eTitleType nTitleIndex
43
    , const rtl::Reference< Diagram >& xDiagram )
44
0
{
45
0
    uno::Reference< XTitled > xResult;
46
47
0
    if( nTitleIndex == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ||
48
0
        nTitleIndex == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
49
0
    {
50
0
        bool bDummy = false;
51
0
        bool bIsVertical = xDiagram && xDiagram->getVertical( bDummy, bDummy );
52
53
0
        if( nTitleIndex == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION )
54
0
            nTitleIndex = bIsVertical ? TitleHelper::X_AXIS_TITLE : TitleHelper::Y_AXIS_TITLE;
55
0
        else
56
0
            nTitleIndex = bIsVertical ? TitleHelper::Y_AXIS_TITLE : TitleHelper::X_AXIS_TITLE;
57
0
    }
58
59
0
    switch( nTitleIndex )
60
0
    {
61
0
        case TitleHelper::SUB_TITLE:
62
0
            if( xDiagram.is())
63
0
                xResult = xDiagram;
64
0
            break;
65
0
        case TitleHelper::X_AXIS_TITLE:
66
0
            if( xDiagram.is())
67
0
                xResult = AxisHelper::getAxis( 0, true, xDiagram );
68
0
            break;
69
0
        case TitleHelper::Y_AXIS_TITLE:
70
0
            if( xDiagram.is())
71
0
                xResult = AxisHelper::getAxis( 1, true, xDiagram );
72
0
            break;
73
0
        case TitleHelper::Z_AXIS_TITLE:
74
0
            if( xDiagram.is())
75
0
                xResult = AxisHelper::getAxis( 2, true, xDiagram );
76
0
            break;
77
0
        case TitleHelper::SECONDARY_X_AXIS_TITLE:
78
0
            if( xDiagram.is())
79
0
                xResult = AxisHelper::getAxis( 0, false, xDiagram );
80
0
            break;
81
0
        case TitleHelper::SECONDARY_Y_AXIS_TITLE:
82
0
            if( xDiagram.is())
83
0
                xResult = AxisHelper::getAxis( 1, false, xDiagram );
84
0
            break;
85
86
0
        case TitleHelper::MAIN_TITLE:
87
0
        default:
88
0
            OSL_FAIL( "Unsupported Title-Type requested" );
89
0
            break;
90
0
    }
91
92
0
    return xResult;
93
0
}
94
95
uno::Reference< XTitled > lcl_getTitleParent( TitleHelper::eTitleType nTitleIndex
96
                                              , const rtl::Reference< Diagram >& xDiagram )
97
0
{
98
0
    uno::Reference< XTitled > xResult;
99
0
    switch( nTitleIndex )
100
0
    {
101
0
        case TitleHelper::MAIN_TITLE:
102
0
            SAL_WARN("chart2", "should not be reached");
103
0
            break;
104
0
        case TitleHelper::SUB_TITLE:
105
0
        case TitleHelper::X_AXIS_TITLE:
106
0
        case TitleHelper::Y_AXIS_TITLE:
107
0
        case TitleHelper::Z_AXIS_TITLE:
108
0
        case TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION:
109
0
        case TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION:
110
0
        case TitleHelper::SECONDARY_X_AXIS_TITLE:
111
0
        case TitleHelper::SECONDARY_Y_AXIS_TITLE:
112
0
            xResult.set( lcl_getTitleParentFromDiagram( nTitleIndex, xDiagram ));
113
0
            break;
114
0
        default:
115
0
            OSL_FAIL( "Unsupported Title-Type requested" );
116
0
            break;
117
0
    }
118
119
0
    return xResult;
120
0
}
121
122
uno::Reference< XTitled > lcl_getTitleParent( TitleHelper::eTitleType nTitleIndex
123
                                              , const rtl::Reference<::chart::ChartModel>& xModel )
124
0
{
125
0
    if(nTitleIndex == TitleHelper::MAIN_TITLE)
126
0
    {
127
0
        return xModel;
128
0
    }
129
130
0
    rtl::Reference< Diagram > xDiagram;
131
132
0
    if( xModel.is())
133
0
        xDiagram = xModel->getFirstChartDiagram();
134
135
0
    return lcl_getTitleParent( nTitleIndex, xDiagram );
136
0
}
137
138
}
139
140
rtl::Reference< Title > TitleHelper::getTitle( TitleHelper::eTitleType nTitleIndex
141
                            , ChartModel& rModel )
142
0
{
143
0
    if(nTitleIndex == TitleHelper::MAIN_TITLE)
144
0
        return rModel.getTitleObject2();
145
146
0
    rtl::Reference< Diagram > xDiagram = rModel.getFirstChartDiagram();
147
0
    uno::Reference< XTitled > xTitled( lcl_getTitleParent( nTitleIndex, xDiagram ) );
148
0
    if( !xTitled )
149
0
        return nullptr;
150
0
    uno::Reference<XTitle> xTitle = xTitled->getTitleObject();
151
0
    auto pTitle = dynamic_cast<Title*>(xTitle.get());
152
0
    assert(!xTitle || pTitle);
153
0
    return pTitle;
154
0
}
155
156
rtl::Reference< Title > TitleHelper::getTitle( TitleHelper::eTitleType nTitleIndex
157
                            , const rtl::Reference<ChartModel>& xModel )
158
0
{
159
0
    uno::Reference< XTitled > xTitled;
160
0
    if(nTitleIndex == TitleHelper::MAIN_TITLE)
161
0
    {
162
0
        xTitled = xModel;
163
0
    }
164
0
    else
165
0
    {
166
0
        rtl::Reference< Diagram > xDiagram;
167
0
        if( xModel.is())
168
0
            xDiagram = xModel->getFirstChartDiagram();
169
0
        xTitled = lcl_getTitleParent( nTitleIndex, xDiagram );
170
0
    }
171
0
    if( !xTitled )
172
0
        return nullptr;
173
0
    uno::Reference<XTitle> xTitle = xTitled->getTitleObject();
174
0
    Title* pTitle = dynamic_cast<Title*>(xTitle.get());
175
0
    assert(!xTitle || pTitle);
176
0
    return pTitle;
177
0
}
178
179
rtl::Reference< Title > TitleHelper::createOrShowTitle(
180
      TitleHelper::eTitleType eTitleType
181
    , const OUString& rTitleText
182
    , const rtl::Reference<ChartModel>& xModel
183
    , const uno::Reference< uno::XComponentContext > & xContext )
184
0
{
185
0
    rtl::Reference< Title > xTitled( TitleHelper::getTitle( eTitleType, xModel ) );
186
0
    if( xTitled.is())
187
0
    {
188
0
        xTitled->setPropertyValue(u"Visible"_ustr,css::uno::Any(true));
189
0
        return xTitled;
190
0
    }
191
0
    else
192
0
    {
193
0
        return createTitle(eTitleType, rTitleText, xModel, xContext, nullptr/*pRefSizeProvider*/);
194
0
    }
195
0
}
196
197
rtl::Reference< Title > TitleHelper::createTitle(
198
      TitleHelper::eTitleType eTitleType
199
    , const OUString& rTitleText
200
    , const rtl::Reference<ChartModel>& xModel
201
    , const uno::Reference< uno::XComponentContext > & xContext
202
    , ReferenceSizeProvider * pRefSizeProvider )
203
0
{
204
0
    rtl::Reference< ::chart::Title > xTitle;
205
0
    uno::Reference< XTitled > xTitled( lcl_getTitleParent( eTitleType, xModel ) );
206
207
0
    if( !xTitled.is() )
208
0
    {
209
0
        rtl::Reference< Diagram > xDiagram( xModel->getFirstChartDiagram() );
210
0
        rtl::Reference< Axis > xAxis;
211
0
        switch( eTitleType )
212
0
        {
213
0
            case TitleHelper::SECONDARY_X_AXIS_TITLE:
214
0
                xAxis = AxisHelper::createAxis( 0, false, xDiagram, xContext );
215
0
                break;
216
0
            case TitleHelper::SECONDARY_Y_AXIS_TITLE:
217
0
                xAxis = AxisHelper::createAxis( 1, false, xDiagram, xContext );
218
0
               break;
219
0
            default:
220
0
               break;
221
0
        }
222
0
        if( xAxis.is() )
223
0
        {
224
0
            xAxis->setPropertyValue( u"Show"_ustr, uno::Any( false ) );
225
0
            xTitled = lcl_getTitleParent( eTitleType, xModel );
226
0
        }
227
0
    }
228
229
0
    if(xTitled.is())
230
0
    {
231
0
        rtl::Reference< Diagram > xDiagram( xModel->getFirstChartDiagram() );
232
233
0
        xTitle = new ::chart::Title();
234
235
        // default char height (main: 13.0 == default)
236
0
        float fDefaultCharHeightSub = 11.0;
237
0
        float fDefaultCharHeightAxis = 9.0;
238
0
        switch( eTitleType )
239
0
        {
240
0
            case TitleHelper::SUB_TITLE:
241
0
                TitleHelper::setCompleteString(
242
0
                    rTitleText, xTitle, xContext, & fDefaultCharHeightSub );
243
0
                break;
244
0
            case TitleHelper::X_AXIS_TITLE:
245
0
            case TitleHelper::Y_AXIS_TITLE:
246
0
            case TitleHelper::Z_AXIS_TITLE:
247
0
            case TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION:
248
0
            case TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION:
249
0
            case TitleHelper::SECONDARY_X_AXIS_TITLE:
250
0
            case TitleHelper::SECONDARY_Y_AXIS_TITLE:
251
0
                TitleHelper::setCompleteString(
252
0
                    rTitleText, xTitle, xContext, & fDefaultCharHeightAxis );
253
0
                break;
254
0
            default:
255
0
                TitleHelper::setCompleteString( rTitleText, xTitle, xContext );
256
0
                break;
257
0
        }
258
259
        // set/clear autoscale
260
0
        if( pRefSizeProvider )
261
0
            pRefSizeProvider->setValuesAtTitle( xTitle );
262
263
0
        xTitled->setTitleObject( xTitle );
264
265
        //default rotation 90 degree for y axis title in normal coordinatesystems or for x axis title for swapped coordinatesystems
266
0
        if( eTitleType == TitleHelper::X_AXIS_TITLE ||
267
0
            eTitleType == TitleHelper::Y_AXIS_TITLE ||
268
0
            eTitleType == TitleHelper::SECONDARY_X_AXIS_TITLE ||
269
0
            eTitleType == TitleHelper::SECONDARY_Y_AXIS_TITLE )
270
271
0
        {
272
0
            try
273
0
            {
274
0
                bool bDummy = false;
275
0
                bool bIsVertical = xDiagram->getVertical( bDummy, bDummy );
276
277
0
                if( (!bIsVertical && eTitleType == TitleHelper::Y_AXIS_TITLE)
278
0
                    || (bIsVertical && eTitleType == TitleHelper::X_AXIS_TITLE)
279
0
                    || (!bIsVertical && eTitleType == TitleHelper::SECONDARY_Y_AXIS_TITLE)
280
0
                    || (bIsVertical && eTitleType == TitleHelper::SECONDARY_X_AXIS_TITLE) )
281
0
                {
282
0
                    xTitle->setPropertyValue( u"TextRotation"_ustr, uno::Any( 90.0 ));
283
0
                }
284
0
            }
285
0
            catch( const uno::Exception & )
286
0
            {
287
0
                DBG_UNHANDLED_EXCEPTION("chart2");
288
0
            }
289
0
        }
290
0
    }
291
0
    return xTitle;
292
293
0
}
294
295
OUString TitleHelper::getCompleteString( const rtl::Reference< Title >& xTitle )
296
0
{
297
0
    if(!xTitle.is())
298
0
        return OUString();
299
0
    OUStringBuffer aRet;
300
0
    const uno::Sequence< uno::Reference< XFormattedString > > aStringList = xTitle->getText();
301
0
    for( uno::Reference< XFormattedString > const & formattedStr : aStringList )
302
0
        aRet.append( formattedStr->getString() );
303
0
    return aRet.makeStringAndClear();
304
0
}
305
306
OUString TitleHelper::getUnstackedStr(const OUString& rNewText)
307
0
{
308
    //#i99841# remove linebreaks that were added for vertical stacking
309
0
    OUStringBuffer aUnstackedStr;
310
0
    OUStringBuffer aSource(rNewText);
311
312
0
    bool bBreakIgnored = false;
313
0
    sal_Int32 nLen = rNewText.getLength();
314
0
    for (sal_Int32 nPos = 0; nPos < nLen; ++nPos)
315
0
    {
316
0
        sal_Unicode aChar = aSource[nPos];
317
0
        if (aChar != '\n')
318
0
        {
319
0
            aUnstackedStr.append(aChar);
320
0
            bBreakIgnored = false;
321
0
        }
322
0
        else if (aChar == '\n' && bBreakIgnored)
323
0
            aUnstackedStr.append(aChar);
324
0
        else
325
0
            bBreakIgnored = true;
326
0
    }
327
0
    return aUnstackedStr.makeStringAndClear();
328
0
}
329
330
void TitleHelper::setFormattedString( const rtl::Reference< Title >& xTitle,
331
    const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& aNewFormattedTitle )
332
0
{
333
0
    if (!xTitle.is() || !aNewFormattedTitle.hasElements())
334
0
        return;
335
336
0
    bool bStacked = false;
337
0
    xTitle->getPropertyValue(u"StackCharacters"_ustr) >>= bStacked;
338
339
0
    if (bStacked)
340
0
    {
341
0
        for (uno::Reference< chart2::XFormattedString >const& formattedStr : aNewFormattedTitle)
342
0
        {
343
0
            formattedStr->setString(TitleHelper::getUnstackedStr(formattedStr->getString()));
344
0
        }
345
0
    }
346
347
0
    xTitle->setText(aNewFormattedTitle);
348
0
}
349
350
void TitleHelper::setCompleteString( const OUString& rNewText
351
                    , const rtl::Reference< Title >& xTitle
352
                    , const uno::Reference< uno::XComponentContext > & xContext
353
                    , const float * pDefaultCharHeight /* = 0 */
354
                    , bool bDialogTitle /*= false*/ )
355
0
{
356
0
    if (!xTitle.is())
357
0
        return;
358
359
0
    bool bStacked = false;
360
0
    if( xTitle.is() )
361
0
        xTitle->getPropertyValue( u"StackCharacters"_ustr ) >>= bStacked;
362
363
0
    OUString aNewText = rNewText;
364
0
    if( bStacked )
365
0
    {
366
0
        aNewText = getUnstackedStr(rNewText);
367
0
    }
368
369
0
    uno::Sequence< uno::Reference< XFormattedString > > aNewStringList;
370
0
    uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText();
371
0
    if( aOldStringList.hasElements())
372
0
    {
373
0
        const OUString aFullString = getCompleteString(xTitle);
374
0
        if (bDialogTitle && aNewText.equals(getUnstackedStr(aFullString)))
375
0
        {
376
            // If the new title setted from a dialog window to a new string
377
            // the first old text portion will be maintained if it's a new string,
378
            // otherwise we use the original one.
379
0
            aNewStringList = std::move(aOldStringList);
380
0
        }
381
0
        else
382
0
        {
383
            // If the new title setted from a dialog to a new string the first
384
            // old text portion will be maintained if there was any. Also in case of ODF
385
            // import which still not support non-uniform formatted titles
386
0
            aNewStringList = { aOldStringList[0] };
387
0
            aNewStringList[0]->setString(aNewText);
388
0
        }
389
0
    }
390
0
    else
391
0
    {
392
0
        uno::Reference< chart2::XFormattedString2 > xFormattedString =
393
0
            chart2::FormattedString::create( xContext );
394
395
0
        xFormattedString->setString( aNewText );
396
0
        aNewStringList = { xFormattedString };
397
0
        if( pDefaultCharHeight != nullptr )
398
0
        {
399
0
            try
400
0
            {
401
0
                uno::Any aFontSize( *pDefaultCharHeight );
402
0
                xFormattedString->setPropertyValue( u"CharHeight"_ustr, aFontSize );
403
0
                xFormattedString->setPropertyValue( u"CharHeightAsian"_ustr, aFontSize );
404
0
                xFormattedString->setPropertyValue( u"CharHeightComplex"_ustr, aFontSize );
405
0
            }
406
0
            catch( const uno::Exception & )
407
0
            {
408
0
                DBG_UNHANDLED_EXCEPTION("chart2");
409
0
            }
410
0
        }
411
0
    }
412
0
    xTitle->setText( aNewStringList );
413
0
}
414
415
void TitleHelper::removeTitle( TitleHelper::eTitleType nTitleIndex
416
                    , const rtl::Reference<ChartModel>& xModel )
417
0
{
418
0
    uno::Reference< XTitled > xTitled( lcl_getTitleParent( nTitleIndex, xModel ) );
419
0
    if( xTitled.is())
420
0
    {
421
0
        xTitled->setTitleObject(nullptr);
422
0
    }
423
0
}
424
425
bool TitleHelper::getTitleType( eTitleType& rType
426
                    , const rtl::Reference< Title >& xTitle
427
                    , const rtl::Reference<ChartModel>& xModel )
428
0
{
429
0
    if( !xTitle.is() || !xModel.is() )
430
0
        return false;
431
432
0
    rtl::Reference< Title > xCurrentTitle;
433
0
    for( sal_Int32 nTitleType = TITLE_BEGIN; nTitleType < NORMAL_TITLE_END; nTitleType++ )
434
0
    {
435
0
        xCurrentTitle = TitleHelper::getTitle( static_cast<eTitleType>(nTitleType), xModel );
436
0
        if( xCurrentTitle == xTitle )
437
0
        {
438
0
            rType = static_cast<eTitleType>(nTitleType);
439
0
            return true;
440
0
        }
441
0
    }
442
443
0
    return false;
444
0
}
445
446
void TitleHelper::hideTitle( TitleHelper::eTitleType nTitleIndex
447
        , const rtl::Reference<ChartModel>& xModel)
448
0
{
449
0
    rtl::Reference< Title > xTitled( TitleHelper::getTitle( nTitleIndex, xModel ) );
450
0
    if( xTitled.is())
451
0
        xTitled->setPropertyValue(u"Visible"_ustr,css::uno::Any(false));
452
0
}
453
454
} //namespace chart
455
456
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */