Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/controller/dialogs/res_Trendline.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 "res_Trendline.hxx"
21
#include <bitmaps.hlst>
22
#include <chartview/ChartSfxItemIds.hxx>
23
24
#include <com/sun/star/chart2/MovingAverageType.hpp>
25
26
#include <svl/intitem.hxx>
27
#include <svl/numformat.hxx>
28
#include <svl/stritem.hxx>
29
#include <vcl/formatter.hxx>
30
#include <vcl/weld.hxx>
31
32
using namespace css::chart2;
33
34
namespace chart
35
{
36
37
static void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue )
38
0
{
39
0
    Formatter& rFieldFormatter = rFmtField.GetFormatter();
40
0
    rFieldFormatter.SetValue(fValue);
41
0
    rFieldFormatter.SetDefaultValue( fValue );
42
0
}
43
44
TrendlineResources::TrendlineResources(weld::Builder& rBuilder, const SfxItemSet& rInAttrs)
45
0
    : m_eTrendLineType(SvxChartRegress::Linear)
46
0
    , m_bTrendLineUnique(true)
47
0
    , m_pNumFormatter(nullptr)
48
0
    , m_nNbPoints(0)
49
0
    , m_xRB_Linear(rBuilder.weld_radio_button(u"linear"_ustr))
50
0
    , m_xRB_Logarithmic(rBuilder.weld_radio_button(u"logarithmic"_ustr))
51
0
    , m_xRB_Exponential(rBuilder.weld_radio_button(u"exponential"_ustr))
52
0
    , m_xRB_Power(rBuilder.weld_radio_button(u"power"_ustr))
53
0
    , m_xRB_Polynomial(rBuilder.weld_radio_button(u"polynomial"_ustr))
54
0
    , m_xRB_MovingAverage(rBuilder.weld_radio_button(u"movingAverage"_ustr))
55
0
    , m_xFI_Linear(rBuilder.weld_image(u"imageLinear"_ustr))
56
0
    , m_xFI_Logarithmic(rBuilder.weld_image(u"imageLogarithmic"_ustr))
57
0
    , m_xFI_Exponential(rBuilder.weld_image(u"imageExponential"_ustr))
58
0
    , m_xFI_Power(rBuilder.weld_image(u"imagePower"_ustr))
59
0
    , m_xFI_Polynomial(rBuilder.weld_image(u"imagePolynomial"_ustr))
60
0
    , m_xFI_MovingAverage(rBuilder.weld_image(u"imageMovingAverage"_ustr))
61
0
    , m_xNF_Degree(rBuilder.weld_spin_button(u"degree"_ustr))
62
0
    , m_xNF_Period(rBuilder.weld_spin_button(u"period"_ustr))
63
0
    , m_xEE_Name(rBuilder.weld_entry(u"entry_name"_ustr))
64
0
    , m_xFmtFld_ExtrapolateForward(rBuilder.weld_formatted_spin_button(u"extrapolateForward"_ustr))
65
0
    , m_xFmtFld_ExtrapolateBackward(rBuilder.weld_formatted_spin_button(u"extrapolateBackward"_ustr))
66
0
    , m_xCB_SetIntercept(rBuilder.weld_check_button(u"setIntercept"_ustr))
67
0
    , m_xFmtFld_InterceptValue(rBuilder.weld_formatted_spin_button(u"interceptValue"_ustr))
68
0
    , m_xCB_ShowEquation(rBuilder.weld_check_button(u"showEquation"_ustr))
69
0
    , m_xEE_XName(rBuilder.weld_entry(u"entry_Xname"_ustr))
70
0
    , m_xEE_YName(rBuilder.weld_entry(u"entry_Yname"_ustr))
71
0
    , m_xCB_ShowCorrelationCoeff(rBuilder.weld_check_button(u"showCorrelationCoefficient"_ustr))
72
0
    , m_xCB_RegressionMovingType(rBuilder.weld_combo_box(u"combo_moving_type"_ustr))
73
0
{
74
0
    FillValueSets();
75
76
0
    Formatter& rForwardFormatter = m_xFmtFld_ExtrapolateForward->GetFormatter();
77
0
    rForwardFormatter.ClearMinValue();
78
0
    rForwardFormatter.ClearMaxValue();
79
0
    Formatter& rBackwardFormatter = m_xFmtFld_ExtrapolateBackward->GetFormatter();
80
0
    rBackwardFormatter.ClearMinValue();
81
0
    rBackwardFormatter.ClearMaxValue();
82
0
    Formatter& rInterceptFormatter = m_xFmtFld_InterceptValue->GetFormatter();
83
0
    rInterceptFormatter.ClearMinValue();
84
0
    rInterceptFormatter.ClearMaxValue();
85
86
0
    Link<weld::Toggleable&,void> aLink = LINK(this, TrendlineResources, SelectTrendLine);
87
0
    m_xRB_Linear->connect_toggled( aLink );
88
0
    m_xRB_Logarithmic->connect_toggled( aLink );
89
0
    m_xRB_Exponential->connect_toggled( aLink );
90
0
    m_xRB_Power->connect_toggled( aLink );
91
0
    m_xRB_Polynomial->connect_toggled( aLink );
92
0
    m_xRB_MovingAverage->connect_toggled( aLink );
93
94
0
    Link<weld::SpinButton&,void> aLink2 = LINK(this, TrendlineResources, ChangeSpinValue);
95
0
    m_xNF_Degree->connect_value_changed(aLink2);
96
0
    m_xNF_Period->connect_value_changed(aLink2);
97
0
    m_xFmtFld_InterceptValue->connect_value_changed(LINK(this, TrendlineResources, ChangeFormattedValue));
98
99
0
    m_xCB_ShowEquation->connect_toggled(LINK(this, TrendlineResources, ShowEquation));
100
101
0
    Reset( rInAttrs );
102
0
    UpdateControlStates();
103
0
}
104
105
TrendlineResources::~TrendlineResources()
106
0
{}
107
108
IMPL_LINK_NOARG(TrendlineResources, SelectTrendLine, weld::Toggleable&, void)
109
0
{
110
0
    if (m_xRB_Linear->get_active())
111
0
        m_eTrendLineType = SvxChartRegress::Linear;
112
0
    else if (m_xRB_Logarithmic->get_active())
113
0
        m_eTrendLineType = SvxChartRegress::Log;
114
0
    else if (m_xRB_Exponential->get_active())
115
0
        m_eTrendLineType = SvxChartRegress::Exp;
116
0
    else if (m_xRB_Power->get_active())
117
0
        m_eTrendLineType = SvxChartRegress::Power;
118
0
    else if (m_xRB_Polynomial->get_active())
119
0
        m_eTrendLineType = SvxChartRegress::Polynomial;
120
0
    else if (m_xRB_MovingAverage->get_active())
121
0
        m_eTrendLineType = SvxChartRegress::MovingAverage;
122
0
    m_bTrendLineUnique = true;
123
124
0
    UpdateControlStates();
125
0
}
126
127
void TrendlineResources::Reset( const SfxItemSet& rInAttrs )
128
0
{
129
0
    if( const SfxStringItem* pCurveNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_CURVE_NAME ) )
130
0
    {
131
0
        OUString aName = pCurveNameItem->GetValue();
132
0
        m_xEE_Name->set_text(aName);
133
0
    }
134
0
    else
135
0
    {
136
0
        m_xEE_Name->set_text(u""_ustr);
137
0
    }
138
0
    if( const SfxStringItem* pRegressionXNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_XNAME ) )
139
0
    {
140
0
        OUString aName = pRegressionXNameItem->GetValue();
141
0
        m_xEE_XName->set_text(aName);
142
0
    }
143
0
    else
144
0
    {
145
0
        m_xEE_XName->set_text(u"x"_ustr);
146
0
    }
147
0
    if( const SfxStringItem* pRegressionYNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_YNAME ) )
148
0
    {
149
0
        OUString aName = pRegressionYNameItem->GetValue();
150
0
        m_xEE_YName->set_text(aName);
151
0
    }
152
0
    else
153
0
    {
154
0
        m_xEE_YName->set_text(u"f(x)"_ustr);
155
0
    }
156
157
0
    const SfxPoolItem* pPoolItem = nullptr;
158
0
    SfxItemState aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_TYPE, true, &pPoolItem );
159
0
    m_bTrendLineUnique = ( aState != SfxItemState::INVALID );
160
0
    if( aState == SfxItemState::SET )
161
0
    {
162
0
        const SvxChartRegressItem * pItem = dynamic_cast< const SvxChartRegressItem * >( pPoolItem );
163
0
        if( pItem )
164
0
        {
165
0
            m_eTrendLineType = pItem->GetValue();
166
0
        }
167
0
    }
168
169
0
    if( const SfxInt32Item* pDegreeItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_DEGREE ) )
170
0
    {
171
0
        sal_Int32 nDegree = pDegreeItem->GetValue();
172
0
        m_xNF_Degree->set_value( nDegree );
173
0
    }
174
0
    else
175
0
    {
176
0
        m_xNF_Degree->set_value( 2 );
177
0
    }
178
179
0
    m_xNF_Degree->save_value();
180
181
0
    if( const SfxInt32Item* pPeriodItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_PERIOD ) )
182
0
    {
183
0
        sal_Int32 nPeriod = pPeriodItem->GetValue();
184
0
        m_xNF_Period->set_value( nPeriod );
185
0
    }
186
0
    else
187
0
    {
188
0
        m_xNF_Period->set_value( 2 );
189
0
    }
190
191
0
    m_xNF_Period->save_value();
192
193
0
    double nValue = 0.0;
194
0
    if( const SvxDoubleItem* pForwardItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) )
195
0
    {
196
0
        nValue = pForwardItem->GetValue() ;
197
0
    }
198
0
    lcl_setValue(*m_xFmtFld_ExtrapolateForward, nValue);
199
200
0
    nValue = 0.0;
201
0
    if( const SvxDoubleItem* pBackwardItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) )
202
0
    {
203
0
        nValue = pBackwardItem->GetValue() ;
204
0
    }
205
0
    lcl_setValue(*m_xFmtFld_ExtrapolateBackward, nValue);
206
207
0
    nValue = 0.0;
208
0
    if( const SvxDoubleItem* pValueItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_INTERCEPT_VALUE ) )
209
0
    {
210
0
        nValue = pValueItem->GetValue() ;
211
0
    }
212
0
    lcl_setValue(*m_xFmtFld_InterceptValue, nValue);
213
214
0
    aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SET_INTERCEPT, true, &pPoolItem );
215
0
    if( aState == SfxItemState::INVALID )
216
0
    {
217
0
        m_xCB_SetIntercept->set_state(TRISTATE_INDET);
218
0
    }
219
0
    else
220
0
    {
221
0
        if( aState == SfxItemState::SET )
222
0
            m_xCB_SetIntercept->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue());
223
0
    }
224
225
0
    aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_EQUATION, true, &pPoolItem );
226
0
    if( aState == SfxItemState::INVALID )
227
0
    {
228
0
        m_xCB_ShowEquation->set_state(TRISTATE_INDET);
229
0
    }
230
0
    else
231
0
    {
232
0
        if( aState == SfxItemState::SET )
233
0
            m_xCB_ShowEquation->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue());
234
0
    }
235
236
0
    aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_COEFF, true, &pPoolItem );
237
0
    if( aState == SfxItemState::INVALID )
238
0
    {
239
0
        m_xCB_ShowCorrelationCoeff->set_state(TRISTATE_INDET);
240
0
    }
241
0
    else
242
0
    {
243
0
        if( aState == SfxItemState::SET )
244
0
            m_xCB_ShowCorrelationCoeff->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue());
245
0
    }
246
247
0
    if( const SfxInt32Item* pMovingTypeItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_MOVING_TYPE ) )
248
0
    {
249
0
        sal_Int32 nMovingType = pMovingTypeItem->GetValue();
250
0
        if (nMovingType == MovingAverageType::Prior)
251
0
            m_xCB_RegressionMovingType->set_active(0);
252
0
        else if (nMovingType == MovingAverageType::Central)
253
0
            m_xCB_RegressionMovingType->set_active(1);
254
0
        else if (nMovingType == MovingAverageType::AveragedAbscissa)
255
0
            m_xCB_RegressionMovingType->set_active(2);
256
0
    }
257
0
    else
258
0
    {
259
0
        m_xCB_RegressionMovingType->set_active(0);
260
0
    }
261
262
0
    if( !m_bTrendLineUnique )
263
0
        return;
264
265
0
    switch( m_eTrendLineType )
266
0
    {
267
0
        case SvxChartRegress::Linear :
268
0
            m_xRB_Linear->set_active(true);
269
0
            break;
270
0
        case SvxChartRegress::Log :
271
0
            m_xRB_Logarithmic->set_active(true);
272
0
            break;
273
0
        case SvxChartRegress::Exp :
274
0
            m_xRB_Exponential->set_active(true);
275
0
            break;
276
0
        case SvxChartRegress::Power :
277
0
            m_xRB_Power->set_active(true);
278
0
            break;
279
0
        case SvxChartRegress::Polynomial :
280
0
            m_xRB_Polynomial->set_active(true);
281
0
            break;
282
0
        case SvxChartRegress::MovingAverage :
283
0
            m_xRB_MovingAverage->set_active(true);
284
0
            break;
285
0
        default:
286
0
            break;
287
0
    }
288
0
}
289
290
void TrendlineResources::FillItemSet(SfxItemSet* rOutAttrs) const
291
0
{
292
0
    if( m_bTrendLineUnique )
293
0
        rOutAttrs->Put( SvxChartRegressItem( m_eTrendLineType, SCHATTR_REGRESSION_TYPE ));
294
295
0
    if (m_eTrendLineType == SvxChartRegress::MovingAverage)
296
0
    {
297
0
        sal_Int32 nType = MovingAverageType::Prior;
298
0
        if (m_xCB_RegressionMovingType->get_active() == 1)
299
0
            nType = MovingAverageType::Central;
300
0
        else if (m_xCB_RegressionMovingType->get_active() == 2)
301
0
            nType = MovingAverageType::AveragedAbscissa;
302
303
0
        rOutAttrs->Put(SfxInt32Item(SCHATTR_REGRESSION_MOVING_TYPE, nType));
304
0
    }
305
306
0
    if( m_xCB_ShowEquation->get_state() != TRISTATE_INDET )
307
0
        rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_EQUATION, m_xCB_ShowEquation->get_active() ));
308
309
0
    if( m_xCB_ShowCorrelationCoeff->get_state() != TRISTATE_INDET )
310
0
        rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_COEFF, m_xCB_ShowCorrelationCoeff->get_active() ));
311
312
0
    OUString aName = m_xEE_Name->get_text();
313
0
    rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_CURVE_NAME, aName));
314
0
    aName = m_xEE_XName->get_text();
315
0
    if ( aName.isEmpty() )
316
0
        aName = "x";
317
0
    rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_XNAME, aName));
318
0
    aName = m_xEE_YName->get_text();
319
0
    if ( aName.isEmpty() )
320
0
        aName = "f(x)";
321
0
    rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_YNAME, aName));
322
323
0
    sal_Int32 aDegree = m_xNF_Degree->get_value();
324
0
    rOutAttrs->Put(SfxInt32Item( SCHATTR_REGRESSION_DEGREE, aDegree ) );
325
326
0
    sal_Int32 aPeriod = m_xNF_Period->get_value();
327
0
    rOutAttrs->Put(SfxInt32Item( SCHATTR_REGRESSION_PERIOD, aPeriod ) );
328
329
0
    sal_uInt32 nIndex = 0;
330
0
    double aValue = 0.0;
331
0
    (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_ExtrapolateForward->get_text(),nIndex,aValue);
332
0
    rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) );
333
334
0
    aValue = 0.0;
335
0
    (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_ExtrapolateBackward->get_text(),nIndex,aValue);
336
0
    rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) );
337
338
0
    if( m_xCB_SetIntercept->get_state() != TRISTATE_INDET )
339
0
        rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SET_INTERCEPT, m_xCB_SetIntercept->get_active() ));
340
341
0
    aValue = 0.0;
342
0
    (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_InterceptValue->get_text(),nIndex,aValue);
343
0
    rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_INTERCEPT_VALUE ) );
344
0
}
345
346
void TrendlineResources::FillValueSets()
347
0
{
348
0
    m_xFI_Linear->set_from_icon_name(BMP_REGRESSION_LINEAR);
349
0
    m_xFI_Logarithmic->set_from_icon_name(BMP_REGRESSION_LOG);
350
0
    m_xFI_Exponential->set_from_icon_name(BMP_REGRESSION_EXP);
351
0
    m_xFI_Power->set_from_icon_name(BMP_REGRESSION_POWER);
352
0
    m_xFI_Polynomial->set_from_icon_name(BMP_REGRESSION_POLYNOMIAL);
353
0
    m_xFI_MovingAverage->set_from_icon_name(BMP_REGRESSION_MOVING_AVERAGE);
354
0
}
355
356
void TrendlineResources::UpdateControlStates()
357
0
{
358
0
    if( m_nNbPoints > 0 )
359
0
    {
360
0
        sal_Int32 nMaxValue = m_nNbPoints - 1 + (m_xCB_SetIntercept->get_active() ? 1 : 0);
361
0
        m_xNF_Degree->set_max(nMaxValue);
362
0
        m_xNF_Period->set_max(m_nNbPoints - 1);
363
0
    }
364
0
    bool bMovingAverage = ( m_eTrendLineType == SvxChartRegress::MovingAverage );
365
0
    bool bPolynomial = ( m_eTrendLineType == SvxChartRegress::Polynomial );
366
0
    bool bInterceptAvailable = ( m_eTrendLineType == SvxChartRegress::Linear )
367
0
                            || ( m_eTrendLineType == SvxChartRegress::Polynomial )
368
0
                            || ( m_eTrendLineType == SvxChartRegress::Exp );
369
0
    m_xFmtFld_ExtrapolateForward->set_sensitive( !bMovingAverage );
370
0
    m_xFmtFld_ExtrapolateBackward->set_sensitive( !bMovingAverage );
371
0
    m_xCB_SetIntercept->set_sensitive( bInterceptAvailable );
372
0
    m_xFmtFld_InterceptValue->set_sensitive( bInterceptAvailable );
373
0
    if( bMovingAverage )
374
0
    {
375
0
        m_xCB_ShowCorrelationCoeff->set_state(TRISTATE_FALSE);
376
0
    }
377
0
    m_xCB_ShowCorrelationCoeff->set_sensitive( !bMovingAverage );
378
0
    m_xCB_RegressionMovingType->set_sensitive(bMovingAverage);
379
0
    m_xNF_Period->set_sensitive(bMovingAverage);
380
0
    m_xNF_Degree->set_sensitive(bPolynomial);
381
0
    m_xEE_XName->set_sensitive( !bMovingAverage && m_xCB_ShowEquation->get_active() );
382
0
    m_xEE_YName->set_sensitive( !bMovingAverage && m_xCB_ShowEquation->get_active() );
383
0
}
384
385
IMPL_LINK(TrendlineResources, ChangeSpinValue, weld::SpinButton&, rNumericField, void)
386
0
{
387
0
    if (&rNumericField == m_xNF_Degree.get())
388
0
    {
389
0
        if (!m_xRB_Polynomial->get_active() && m_xNF_Degree->get_value_changed_from_saved())
390
0
        {
391
0
            m_xRB_Polynomial->set_active(true);
392
0
            SelectTrendLine(*m_xRB_Polynomial);
393
0
        }
394
0
    }
395
0
    else if (&rNumericField == m_xNF_Period.get())
396
0
    {
397
0
        if (!m_xRB_MovingAverage->get_active() && m_xNF_Period->get_value_changed_from_saved())
398
0
        {
399
0
            m_xRB_MovingAverage->set_active(true);
400
0
            SelectTrendLine(*m_xRB_MovingAverage);
401
0
        }
402
0
    }
403
0
    UpdateControlStates();
404
0
}
405
406
IMPL_LINK_NOARG(TrendlineResources, ChangeFormattedValue, weld::FormattedSpinButton&, void)
407
0
{
408
0
    if (!m_xCB_SetIntercept->get_active())
409
0
        m_xCB_SetIntercept->set_active(true);
410
0
    UpdateControlStates();
411
0
}
412
413
void TrendlineResources::SetNumFormatter( SvNumberFormatter* pFormatter )
414
0
{
415
0
    m_pNumFormatter = pFormatter;
416
0
    m_xFmtFld_ExtrapolateForward->GetFormatter().SetFormatter(m_pNumFormatter);
417
0
    m_xFmtFld_ExtrapolateBackward->GetFormatter().SetFormatter(m_pNumFormatter);
418
0
    m_xFmtFld_InterceptValue->GetFormatter().SetFormatter(m_pNumFormatter);
419
0
}
420
421
void TrendlineResources::SetNbPoints( sal_Int32 nNbPoints )
422
0
{
423
0
    m_nNbPoints = nNbPoints;
424
0
    UpdateControlStates();
425
0
}
426
427
IMPL_LINK_NOARG(TrendlineResources, ShowEquation, weld::Toggleable&, void)
428
0
{
429
0
    UpdateControlStates();
430
0
}
431
432
} //  namespace chart
433
434
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */