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