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 #ifdef SC_DLLIMPLEMENTATION
21 #undef SC_DLLIMPLEMENTATION
22 #endif
23 
24 #include <dpgroupdlg.hxx>
25 #include <globstr.hrc>
26 #include <scresid.hxx>
27 #include <editfield.hxx>
28 
29 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
30 #include <svtools/ctrlbox.hxx>
31 
32 namespace {
33 
34 /** Date part flags in order of the list box entries. */
35 const sal_Int32 spnDateParts[] =
36 {
37     css::sheet::DataPilotFieldGroupBy::SECONDS,
38     css::sheet::DataPilotFieldGroupBy::MINUTES,
39     css::sheet::DataPilotFieldGroupBy::HOURS,
40     css::sheet::DataPilotFieldGroupBy::DAYS,
41     css::sheet::DataPilotFieldGroupBy::MONTHS,
42     css::sheet::DataPilotFieldGroupBy::QUARTERS,
43     css::sheet::DataPilotFieldGroupBy::YEARS
44 };
45 
46 const char* aDatePartResIds[] =
47 {
48     STR_DPFIELD_GROUP_BY_SECONDS,
49     STR_DPFIELD_GROUP_BY_MINUTES,
50     STR_DPFIELD_GROUP_BY_HOURS,
51     STR_DPFIELD_GROUP_BY_DAYS,
52     STR_DPFIELD_GROUP_BY_MONTHS,
53     STR_DPFIELD_GROUP_BY_QUARTERS,
54     STR_DPFIELD_GROUP_BY_YEARS
55 };
56 
57 } // namespace
58 
ScDPGroupEditHelper(weld::RadioButton & rRbAuto,weld::RadioButton & rRbMan,weld::Widget & rEdValue)59 ScDPGroupEditHelper::ScDPGroupEditHelper(weld::RadioButton& rRbAuto, weld::RadioButton& rRbMan, weld::Widget& rEdValue)
60     : mrRbAuto(rRbAuto)
61     , mrRbMan(rRbMan)
62     , mrEdValue(rEdValue)
63 {
64     mrRbAuto.connect_toggled( LINK( this, ScDPGroupEditHelper, ToggleHdl ) );
65     mrRbMan.connect_toggled( LINK( this, ScDPGroupEditHelper, ToggleHdl ) );
66 }
67 
IsAuto() const68 bool ScDPGroupEditHelper::IsAuto() const
69 {
70     return mrRbAuto.get_active();
71 }
72 
GetValue() const73 double ScDPGroupEditHelper::GetValue() const
74 {
75     double fValue;
76     if( !ImplGetValue( fValue ) )
77         fValue = 0.0;
78     return fValue;
79 }
80 
SetValue(bool bAuto,double fValue)81 void ScDPGroupEditHelper::SetValue( bool bAuto, double fValue )
82 {
83     if( bAuto )
84     {
85         mrRbAuto.set_active(true);
86         ToggleHdl(mrRbAuto);
87     }
88     else
89     {
90         mrRbMan.set_active(true);
91         ToggleHdl(mrRbMan);
92     }
93     ImplSetValue( fValue );
94 }
95 
IMPL_LINK(ScDPGroupEditHelper,ToggleHdl,weld::Toggleable &,rButton,void)96 IMPL_LINK(ScDPGroupEditHelper, ToggleHdl, weld::Toggleable&, rButton, void)
97 {
98     if (!rButton.get_active())
99         return;
100 
101     if (mrRbAuto.get_active())
102     {
103         // disable edit field on clicking "automatic" radio button
104         mrEdValue.set_sensitive(false);
105     }
106     else if (mrRbMan.get_active())
107     {
108         // enable and set focus to edit field on clicking "manual" radio button
109         mrEdValue.set_sensitive(true);
110         mrEdValue.grab_focus();
111     }
112 }
113 
ScDPNumGroupEditHelper(weld::RadioButton & rRbAuto,weld::RadioButton & rRbMan,ScDoubleField & rEdValue)114 ScDPNumGroupEditHelper::ScDPNumGroupEditHelper(weld::RadioButton& rRbAuto,
115     weld::RadioButton& rRbMan, ScDoubleField& rEdValue)
116     : ScDPGroupEditHelper(rRbAuto, rRbMan, rEdValue.get_widget())
117     , mrEdValue(rEdValue)
118 {
119 }
120 
ImplGetValue(double & rfValue) const121 bool ScDPNumGroupEditHelper::ImplGetValue( double& rfValue ) const
122 {
123     return mrEdValue.GetValue(rfValue);
124 }
125 
ImplSetValue(double fValue)126 void ScDPNumGroupEditHelper::ImplSetValue( double fValue )
127 {
128     mrEdValue.SetValue(fValue);
129 }
130 
ScDPDateGroupEditHelper(weld::RadioButton & rRbAuto,weld::RadioButton & rRbMan,SvtCalendarBox & rEdValue,const Date & rNullDate)131 ScDPDateGroupEditHelper::ScDPDateGroupEditHelper(weld::RadioButton& rRbAuto, weld::RadioButton& rRbMan,
132                                                  SvtCalendarBox& rEdValue, const Date& rNullDate)
133     : ScDPGroupEditHelper(rRbAuto, rRbMan, rEdValue.get_button())
134     , mrEdValue(rEdValue)
135     , maNullDate(rNullDate)
136 {
137 }
138 
ImplGetValue(double & rfValue) const139 bool ScDPDateGroupEditHelper::ImplGetValue( double& rfValue ) const
140 {
141     rfValue = mrEdValue.get_date() - maNullDate;
142     return true;
143 }
144 
ImplSetValue(double fValue)145 void ScDPDateGroupEditHelper::ImplSetValue( double fValue )
146 {
147     Date aDate( maNullDate );
148     aDate.AddDays( fValue );
149     mrEdValue.set_date( aDate );
150 }
151 
ScDPNumGroupDlg(weld::Window * pParent,const ScDPNumGroupInfo & rInfo)152 ScDPNumGroupDlg::ScDPNumGroupDlg(weld::Window* pParent, const ScDPNumGroupInfo& rInfo)
153     : GenericDialogController(pParent, "modules/scalc/ui/groupbynumber.ui", "PivotTableGroupByNumber")
154     , mxRbAutoStart(m_xBuilder->weld_radio_button("auto_start"))
155     , mxRbManStart(m_xBuilder->weld_radio_button("manual_start"))
156     , mxEdStart(new ScDoubleField(m_xBuilder->weld_entry("edit_start")))
157     , mxRbAutoEnd(m_xBuilder->weld_radio_button("auto_end"))
158     , mxRbManEnd(m_xBuilder->weld_radio_button("manual_end"))
159     , mxEdEnd(new ScDoubleField(m_xBuilder->weld_entry("edit_end")))
160     , mxEdBy(new ScDoubleField(m_xBuilder->weld_entry("edit_by")))
161     , maStartHelper(*mxRbAutoStart, *mxRbManStart, *mxEdStart)
162     , maEndHelper(*mxRbAutoEnd, *mxRbManEnd, *mxEdEnd)
163 {
164     maStartHelper.SetValue( rInfo.mbAutoStart, rInfo.mfStart );
165     maEndHelper.SetValue( rInfo.mbAutoEnd, rInfo.mfEnd );
166     mxEdBy->SetValue( (rInfo.mfStep <= 0.0) ? 1.0 : rInfo.mfStep );
167 
168     /*  Set the initial focus, currently it is somewhere after calling all the radio
169         button click handlers. Now the first enabled editable control is focused. */
170     if (mxEdStart->get_sensitive())
171         mxEdStart->grab_focus();
172     else if (mxEdEnd->get_sensitive())
173         mxEdEnd->grab_focus();
174     else
175         mxEdBy->grab_focus();
176 }
177 
~ScDPNumGroupDlg()178 ScDPNumGroupDlg::~ScDPNumGroupDlg()
179 {
180 }
181 
GetGroupInfo() const182 ScDPNumGroupInfo ScDPNumGroupDlg::GetGroupInfo() const
183 {
184     ScDPNumGroupInfo aInfo;
185     aInfo.mbEnable = true;
186     aInfo.mbDateValues = false;
187     aInfo.mbAutoStart = maStartHelper.IsAuto();
188     aInfo.mbAutoEnd = maEndHelper.IsAuto();
189 
190     // get values and silently auto-correct them, if they are not valid
191     // TODO: error messages in OK event?
192     aInfo.mfStart = maStartHelper.GetValue();
193     aInfo.mfEnd = maEndHelper.GetValue();
194     if( !mxEdBy->GetValue( aInfo.mfStep ) || (aInfo.mfStep <= 0.0) )
195         aInfo.mfStep = 1.0;
196     if( aInfo.mfEnd <= aInfo.mfStart )
197         aInfo.mfEnd = aInfo.mfStart + aInfo.mfStep;
198 
199     return aInfo;
200 }
201 
ScDPDateGroupDlg(weld::Window * pParent,const ScDPNumGroupInfo & rInfo,sal_Int32 nDatePart,const Date & rNullDate)202 ScDPDateGroupDlg::ScDPDateGroupDlg(weld::Window* pParent,
203         const ScDPNumGroupInfo& rInfo, sal_Int32 nDatePart, const Date& rNullDate)
204     : GenericDialogController(pParent, "modules/scalc/ui/groupbydate.ui", "PivotTableGroupByDate")
205     , mxRbAutoStart(m_xBuilder->weld_radio_button("auto_start"))
206     , mxRbManStart(m_xBuilder->weld_radio_button("manual_start"))
207     , mxEdStart(new SvtCalendarBox(m_xBuilder->weld_menu_button("start_date")))
208     , mxRbAutoEnd(m_xBuilder->weld_radio_button("auto_end"))
209     , mxRbManEnd(m_xBuilder->weld_radio_button("manual_end"))
210     , mxEdEnd(new SvtCalendarBox(m_xBuilder->weld_menu_button("end_date")))
211     , mxRbNumDays(m_xBuilder->weld_radio_button("days"))
212     , mxRbUnits(m_xBuilder->weld_radio_button("intervals"))
213     , mxEdNumDays(m_xBuilder->weld_spin_button("days_value"))
214     , mxLbUnits(m_xBuilder->weld_tree_view("interval_list"))
215     , mxBtnOk(m_xBuilder->weld_button("ok"))
216     , maStartHelper(*mxRbAutoStart, *mxRbManStart, *mxEdStart, rNullDate)
217     , maEndHelper(*mxRbAutoEnd, *mxRbManEnd, *mxEdEnd, rNullDate)
218 {
219     maStartHelper.SetValue( rInfo.mbAutoStart, rInfo.mfStart );
220     maEndHelper.SetValue( rInfo.mbAutoEnd, rInfo.mfEnd );
221 
222     mxLbUnits->enable_toggle_buttons(weld::ColumnToggleType::Check);
223 
224     if( nDatePart == 0 )
225         nDatePart = css::sheet::DataPilotFieldGroupBy::MONTHS;
226     for (size_t nIdx = 0; nIdx < SAL_N_ELEMENTS(aDatePartResIds); ++nIdx)
227     {
228         mxLbUnits->append();
229         mxLbUnits->set_toggle(nIdx, (nDatePart & spnDateParts[ nIdx ]) ? TRISTATE_TRUE : TRISTATE_FALSE);
230         mxLbUnits->set_text(nIdx, ScResId(aDatePartResIds[nIdx]), 0);
231     }
232 
233     if( rInfo.mbDateValues )
234     {
235         mxRbNumDays->set_active(true);
236         ToggleHdl(*mxRbNumDays );
237 
238         double fNumDays = rInfo.mfStep;
239         if( fNumDays < 1.0 )
240             fNumDays = 1.0;
241         else if( fNumDays > 32767.0 )
242             fNumDays = 32767.0;
243         mxEdNumDays->set_value(fNumDays);
244     }
245     else
246     {
247         mxRbUnits->set_active(true);
248         ToggleHdl(*mxRbUnits);
249     }
250 
251     /*  Set the initial focus, currently it is somewhere after calling all the radio
252         button click handlers. Now the first enabled editable control is focused. */
253     if( mxEdStart->get_sensitive() )
254         mxEdStart->grab_focus();
255     else if( mxEdEnd->get_sensitive() )
256         mxEdEnd->grab_focus();
257     else if( mxEdNumDays->get_sensitive() )
258         mxEdNumDays->grab_focus();
259     else if( mxLbUnits->get_sensitive() )
260         mxLbUnits->grab_focus();
261 
262     mxRbNumDays->connect_toggled( LINK( this, ScDPDateGroupDlg, ToggleHdl ) );
263     mxRbUnits->connect_toggled( LINK( this, ScDPDateGroupDlg, ToggleHdl ) );
264     mxLbUnits->connect_toggled( LINK( this, ScDPDateGroupDlg, CheckHdl ) );
265 }
266 
~ScDPDateGroupDlg()267 ScDPDateGroupDlg::~ScDPDateGroupDlg()
268 {
269 }
270 
GetGroupInfo() const271 ScDPNumGroupInfo ScDPDateGroupDlg::GetGroupInfo() const
272 {
273     ScDPNumGroupInfo aInfo;
274     aInfo.mbEnable = true;
275     aInfo.mbDateValues = mxRbNumDays->get_active();
276     aInfo.mbAutoStart = maStartHelper.IsAuto();
277     aInfo.mbAutoEnd = maEndHelper.IsAuto();
278 
279     // get values and silently auto-correct them, if they are not valid
280     // TODO: error messages in OK event?
281     aInfo.mfStart = maStartHelper.GetValue();
282     aInfo.mfEnd = maEndHelper.GetValue();
283     sal_Int64 nNumDays = mxEdNumDays->get_value();
284     aInfo.mfStep = static_cast<double>( aInfo.mbDateValues ? nNumDays : 0L );
285     if( aInfo.mfEnd <= aInfo.mfStart )
286         aInfo.mfEnd = aInfo.mfStart + nNumDays;
287 
288     return aInfo;
289 }
290 
GetDatePart() const291 sal_Int32 ScDPDateGroupDlg::GetDatePart() const
292 {
293     // return DAYS for special "number of days" mode
294     if( mxRbNumDays->get_active() )
295         return css::sheet::DataPilotFieldGroupBy::DAYS;
296 
297     // return listbox contents for "units" mode
298     sal_Int32 nDatePart = 0;
299     for (int nIdx = 0, nCount = mxLbUnits->n_children(); nIdx < nCount; ++nIdx )
300         if (mxLbUnits->get_toggle(nIdx) == TRISTATE_TRUE)
301             nDatePart |= spnDateParts[ nIdx ];
302     return nDatePart;
303 }
304 
IMPL_LINK(ScDPDateGroupDlg,ToggleHdl,weld::Toggleable &,rButton,void)305 IMPL_LINK(ScDPDateGroupDlg, ToggleHdl, weld::Toggleable&, rButton, void)
306 {
307     if (!rButton.get_active())
308         return;
309     if (mxRbNumDays->get_active())
310     {
311         mxLbUnits->set_sensitive(false);
312         // enable and set focus to edit field on clicking "num of days" radio button
313         mxEdNumDays->set_sensitive(true);
314         mxEdNumDays->grab_focus();
315         mxBtnOk->set_sensitive(true);
316     }
317     else if (mxRbUnits->get_active())
318     {
319         mxEdNumDays->set_sensitive(false);
320         // enable and set focus to listbox on clicking "units" radio button
321         mxLbUnits->set_sensitive(true);
322         mxLbUnits->grab_focus();
323         // disable OK button if no date part selected
324         Check();
325     }
326 }
327 
328 namespace
329 {
HasCheckedEntryCount(const weld::TreeView & rView)330     bool HasCheckedEntryCount(const weld::TreeView& rView)
331     {
332         for (int i = 0; i < rView.n_children(); ++i)
333         {
334             if (rView.get_toggle(i) == TRISTATE_TRUE)
335                 return true;
336         }
337         return false;
338     }
339 }
340 
IMPL_LINK_NOARG(ScDPDateGroupDlg,CheckHdl,const weld::TreeView::iter_col &,void)341 IMPL_LINK_NOARG(ScDPDateGroupDlg, CheckHdl, const weld::TreeView::iter_col&, void)
342 {
343     Check();
344 }
345 
Check()346 void ScDPDateGroupDlg::Check()
347 {
348     // enable/disable OK button on modifying check list box
349     mxBtnOk->set_sensitive(HasCheckedEntryCount(*mxLbUnits));
350 }
351 
352 
353 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
354