1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
11 #include <sfx2/dispatch.hxx>
12 #include <svl/zforlist.hxx>
13 #include <svl/undo.hxx>
14 #include <comphelper/random.hxx>
15 #include "rangelst.hxx"
16 #include "scitems.hxx"
18 #include "document.hxx"
19 #include "uiitems.hxx"
20 #include "reffact.hxx"
21 #include "strload.hxx"
22 #include "docfunc.hxx"
23 #include "StatisticsDialogs.hrc"
25 #include "SamplingDialog.hxx"
27 ScSamplingDialog::ScSamplingDialog(
28 SfxBindings
* pSfxBindings
, SfxChildWindow
* pChildWindow
,
29 vcl::Window
* pParent
, ScViewData
* pViewData
) :
30 ScAnyRefDlg ( pSfxBindings
, pChildWindow
, pParent
,
31 "SamplingDialog", "modules/scalc/ui/samplingdialog.ui" ),
32 mpActiveEdit ( NULL
),
33 mViewData ( pViewData
),
34 mDocument ( pViewData
->GetDocument() ),
35 mInputRange ( ScAddress::INITIALIZE_INVALID
),
36 mAddressDetails ( mDocument
->GetAddressConvention(), 0, 0 ),
37 mOutputAddress ( ScAddress::INITIALIZE_INVALID
),
38 mCurrentAddress ( pViewData
->GetCurX(), pViewData
->GetCurY(), pViewData
->GetTabNo() ),
39 mDialogLostFocus( false )
41 get(mpInputRangeLabel
, "input-range-label");
42 get(mpInputRangeEdit
, "input-range-edit");
43 get(mpInputRangeButton
, "input-range-button");
44 mpInputRangeEdit
->SetReferences(this, mpInputRangeLabel
);
45 mpInputRangeButton
->SetReferences(this, mpInputRangeEdit
);
47 get(mpOutputRangeLabel
, "output-range-label");
48 get(mpOutputRangeEdit
, "output-range-edit");
49 get(mpOutputRangeButton
, "output-range-button");
50 mpOutputRangeEdit
->SetReferences(this, mpOutputRangeLabel
);
51 mpOutputRangeButton
->SetReferences(this, mpOutputRangeEdit
);
53 get(mpSampleSize
, "sample-size-spin");
54 get(mpPeriod
, "period-spin");
56 get(mpRandomMethodRadio
, "random-method-radio");
57 get(mpPeriodicMethodRadio
, "periodic-method-radio");
59 get(mpButtonOk
, "ok");
62 GetRangeFromSelection();
65 ScSamplingDialog::~ScSamplingDialog()
70 void ScSamplingDialog::dispose()
72 mpInputRangeLabel
.clear();
73 mpInputRangeEdit
.clear();
74 mpInputRangeButton
.clear();
75 mpOutputRangeLabel
.clear();
76 mpOutputRangeEdit
.clear();
77 mpOutputRangeButton
.clear();
80 mpRandomMethodRadio
.clear();
81 mpPeriodicMethodRadio
.clear();
84 ScAnyRefDlg::dispose();
87 void ScSamplingDialog::Init()
89 mpButtonOk
->SetClickHdl( LINK( this, ScSamplingDialog
, OkClicked
) );
90 mpButtonOk
->Enable(false);
92 Link
<> aLink
= LINK( this, ScSamplingDialog
, GetFocusHandler
);
93 mpInputRangeEdit
->SetGetFocusHdl( aLink
);
94 mpInputRangeButton
->SetGetFocusHdl( aLink
);
95 mpOutputRangeEdit
->SetGetFocusHdl( aLink
);
96 mpOutputRangeButton
->SetGetFocusHdl( aLink
);
98 aLink
= LINK( this, ScSamplingDialog
, LoseFocusHandler
);
99 mpInputRangeEdit
->SetLoseFocusHdl( aLink
);
100 mpInputRangeButton
->SetLoseFocusHdl( aLink
);
101 mpOutputRangeEdit
->SetLoseFocusHdl( aLink
);
102 mpOutputRangeButton
->SetLoseFocusHdl( aLink
);
104 aLink
= LINK( this, ScSamplingDialog
, RefInputModifyHandler
);
105 mpInputRangeEdit
->SetModifyHdl( aLink
);
106 mpOutputRangeEdit
->SetModifyHdl( aLink
);
108 mpSampleSize
->SetModifyHdl( LINK( this, ScSamplingDialog
, SamplingSizeValueModified
));
110 mpPeriodicMethodRadio
->SetToggleHdl( LINK( this, ScSamplingDialog
, ToggleSamplingMethod
) );
111 mpRandomMethodRadio
->SetToggleHdl( LINK( this, ScSamplingDialog
, ToggleSamplingMethod
) );
113 mpSampleSize
->SetMin( 0 );
114 mpSampleSize
->SetMax( SAL_MAX_INT64
);
116 mpOutputRangeEdit
->GrabFocus();
117 mpPeriodicMethodRadio
->Check(true);
119 ToggleSamplingMethod(NULL
);
122 void ScSamplingDialog::GetRangeFromSelection()
124 mViewData
->GetSimpleArea(mInputRange
);
125 OUString
aCurrentString(mInputRange
.Format(SCR_ABS_3D
, mDocument
, mAddressDetails
));
126 mpInputRangeEdit
->SetText(aCurrentString
);
129 void ScSamplingDialog::SetActive()
131 if ( mDialogLostFocus
)
133 mDialogLostFocus
= false;
135 mpActiveEdit
->GrabFocus();
144 bool ScSamplingDialog::Close()
146 return DoClose( ScSamplingDialogWrapper::GetChildWindowId() );
149 void ScSamplingDialog::SetReference( const ScRange
& rReferenceRange
, ScDocument
* pDocument
)
153 if ( rReferenceRange
.aStart
!= rReferenceRange
.aEnd
)
154 RefInputStart( mpActiveEdit
);
156 OUString aReferenceString
;
158 if ( mpActiveEdit
== mpInputRangeEdit
)
160 mInputRange
= rReferenceRange
;
161 aReferenceString
= mInputRange
.Format(SCR_ABS_3D
, pDocument
, mAddressDetails
);
162 mpInputRangeEdit
->SetRefString( aReferenceString
);
164 else if ( mpActiveEdit
== mpOutputRangeEdit
)
166 mOutputAddress
= rReferenceRange
.aStart
;
168 sal_uInt16 nFormat
= ( mOutputAddress
.Tab() == mCurrentAddress
.Tab() ) ? SCA_ABS
: SCA_ABS_3D
;
169 aReferenceString
= mOutputAddress
.Format(nFormat
, pDocument
, pDocument
->GetAddressConvention());
170 mpOutputRangeEdit
->SetRefString( aReferenceString
);
172 // Change sampling size according to output range selection
173 sal_Int64 aSelectedSampleSize
= rReferenceRange
.aEnd
.Row() - rReferenceRange
.aStart
.Row() + 1;
174 if (aSelectedSampleSize
> 1)
175 mpSampleSize
->SetValue(aSelectedSampleSize
);
176 SamplingSizeValueModified(NULL
);
180 // Enable OK if both, input range and output address are set.
181 if (mInputRange
.IsValid() && mOutputAddress
.IsValid())
182 mpButtonOk
->Enable();
185 ScRange
ScSamplingDialog::PerformPeriodicSampling(ScDocShell
* pDocShell
)
187 ScAddress aStart
= mInputRange
.aStart
;
188 ScAddress aEnd
= mInputRange
.aEnd
;
190 SCTAB outTab
= mOutputAddress
.Tab();
191 SCCOL outCol
= mOutputAddress
.Col();
192 SCROW outRow
= mOutputAddress
.Row();
194 sal_Int64 aPeriod
= mpPeriod
->GetValue();
196 for (SCROW inTab
= aStart
.Tab(); inTab
<= aEnd
.Tab(); inTab
++)
198 outCol
= mOutputAddress
.Col();
199 for (SCCOL inCol
= aStart
.Col(); inCol
<= aEnd
.Col(); inCol
++)
202 outRow
= mOutputAddress
.Row();
203 for (SCROW inRow
= aStart
.Row(); inRow
<= aEnd
.Row(); inRow
++)
205 if (i
% aPeriod
== aPeriod
- 1 ) // Sample the last of period
207 double aValue
= mDocument
->GetValue(ScAddress(inCol
, inRow
, inTab
));
208 pDocShell
->GetDocFunc().SetValueCell(ScAddress(outCol
, outRow
, outTab
), aValue
, true);
218 return ScRange(mOutputAddress
, ScAddress(outTab
, outRow
, outTab
) );
221 ScRange
ScSamplingDialog::PerformRandomSampling(ScDocShell
* pDocShell
)
223 ScAddress aStart
= mInputRange
.aStart
;
224 ScAddress aEnd
= mInputRange
.aEnd
;
226 SCTAB outTab
= mOutputAddress
.Tab();
227 SCCOL outCol
= mOutputAddress
.Col();
228 SCROW outRow
= mOutputAddress
.Row();
232 sal_Int64 aSampleSize
= mpSampleSize
->GetValue();
234 for (SCROW inTab
= aStart
.Tab(); inTab
<= aEnd
.Tab(); inTab
++)
236 outCol
= mOutputAddress
.Col();
237 for (SCCOL inCol
= aStart
.Col(); inCol
<= aEnd
.Col(); inCol
++)
239 SCROW aPopulationSize
= (aEnd
.Row() - aStart
.Row()) + 1;
241 outRow
= mOutputAddress
.Row();
242 inRow
= aStart
.Row();
244 while ((outRow
- mOutputAddress
.Row()) < aSampleSize
)
246 double aRandomValue
= comphelper::rng::uniform_real_distribution();
248 if ( (aPopulationSize
- (inRow
- aStart
.Row())) * aRandomValue
>= aSampleSize
- (outRow
- mOutputAddress
.Row()) )
254 double aValue
= mDocument
->GetValue( ScAddress(inCol
, inRow
, inTab
) );
255 pDocShell
->GetDocFunc().SetValueCell(ScAddress(outCol
, outRow
, outTab
), aValue
, true);
265 return ScRange(mOutputAddress
, ScAddress(outTab
, outRow
, outTab
) );
268 void ScSamplingDialog::PerformSampling()
270 OUString
aUndo( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_SAMPLING_UNDO_NAME
));
271 ScDocShell
* pDocShell
= mViewData
->GetDocShell();
272 svl::IUndoManager
* pUndoManager
= pDocShell
->GetUndoManager();
274 ScRange aModifiedRange
;
276 pUndoManager
->EnterListAction( aUndo
, aUndo
);
278 if (mpRandomMethodRadio
->IsChecked())
280 aModifiedRange
= PerformRandomSampling(pDocShell
);
282 else if (mpPeriodicMethodRadio
->IsChecked())
284 aModifiedRange
= PerformPeriodicSampling(pDocShell
);
287 pUndoManager
->LeaveListAction();
288 pDocShell
->PostPaint(aModifiedRange
, PAINT_GRID
);
291 IMPL_LINK( ScSamplingDialog
, OkClicked
, PushButton
*, /*pButton*/ )
298 IMPL_LINK( ScSamplingDialog
, GetFocusHandler
, Control
*, pCtrl
)
302 if( (pCtrl
== (Control
*) mpInputRangeEdit
) || (pCtrl
== (Control
*) mpInputRangeButton
) )
303 mpActiveEdit
= mpInputRangeEdit
;
304 else if( (pCtrl
== (Control
*) mpOutputRangeEdit
) || (pCtrl
== (Control
*) mpOutputRangeButton
) )
305 mpActiveEdit
= mpOutputRangeEdit
;
308 mpActiveEdit
->SetSelection( Selection( 0, SELECTION_MAX
) );
313 IMPL_LINK_NOARG(ScSamplingDialog
, LoseFocusHandler
)
315 mDialogLostFocus
= !IsActive();
319 IMPL_LINK_NOARG(ScSamplingDialog
, SamplingSizeValueModified
)
321 sal_Int64 aPopulationSize
= mInputRange
.aEnd
.Row() - mInputRange
.aStart
.Row() + 1;
322 if (mpSampleSize
->GetValue() > aPopulationSize
)
323 mpSampleSize
->SetValue(aPopulationSize
);
327 IMPL_LINK_NOARG(ScSamplingDialog
, ToggleSamplingMethod
)
329 if (mpRandomMethodRadio
->IsChecked())
331 mpPeriod
->Enable(false);
332 mpSampleSize
->Enable(true);
334 else if (mpPeriodicMethodRadio
->IsChecked())
336 mpPeriod
->Enable(true);
337 mpSampleSize
->Enable(false);
342 IMPL_LINK_NOARG(ScSamplingDialog
, RefInputModifyHandler
)
346 if ( mpActiveEdit
== mpInputRangeEdit
)
348 ScRangeList aRangeList
;
349 bool bValid
= ParseWithNames( aRangeList
, mpInputRangeEdit
->GetText(), mDocument
);
350 const ScRange
* pRange
= (bValid
&& aRangeList
.size() == 1) ? aRangeList
[0] : nullptr;
353 mInputRange
= *pRange
;
354 // Highlight the resulting range.
355 mpInputRangeEdit
->StartUpdateData();
359 mInputRange
= ScRange( ScAddress::INITIALIZE_INVALID
);
362 else if ( mpActiveEdit
== mpOutputRangeEdit
)
364 ScRangeList aRangeList
;
365 bool bValid
= ParseWithNames( aRangeList
, mpOutputRangeEdit
->GetText(), mDocument
);
366 const ScRange
* pRange
= (bValid
&& aRangeList
.size() == 1) ? aRangeList
[0] : nullptr;
369 mOutputAddress
= pRange
->aStart
;
371 // Crop output range to top left address for Edit field.
372 if (pRange
->aStart
!= pRange
->aEnd
)
374 sal_uInt16 nFormat
= ( mOutputAddress
.Tab() == mCurrentAddress
.Tab() ) ? SCA_ABS
: SCA_ABS_3D
;
375 OUString aReferenceString
= mOutputAddress
.Format(nFormat
, mDocument
, mDocument
->GetAddressConvention());
376 mpOutputRangeEdit
->SetRefString( aReferenceString
);
379 // Change sampling size according to output range selection
380 sal_Int64 aSelectedSampleSize
= pRange
->aEnd
.Row() - pRange
->aStart
.Row() + 1;
381 if (aSelectedSampleSize
> 1)
382 mpSampleSize
->SetValue(aSelectedSampleSize
);
383 SamplingSizeValueModified(NULL
);
385 // Highlight the resulting range.
386 mpOutputRangeEdit
->StartUpdateData();
390 mOutputAddress
= ScAddress( ScAddress::INITIALIZE_INVALID
);
395 // Enable OK if both, input range and output address are set.
396 if (mInputRange
.IsValid() && mOutputAddress
.IsValid())
397 mpButtonOk
->Enable();
399 mpButtonOk
->Disable();
404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */