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 <rtl/math.hxx>
16 #include "rangelst.hxx"
17 #include "scitems.hxx"
19 #include "document.hxx"
20 #include "uiitems.hxx"
21 #include "reffact.hxx"
22 #include "strload.hxx"
23 #include "docfunc.hxx"
24 #include "StatisticsDialogs.hrc"
28 #include "RandomNumberGeneratorDialog.hxx"
33 const sal_Int64 DIST_UNIFORM
= 0;
34 const sal_Int64 DIST_NORMAL
= 1;
35 const sal_Int64 DIST_CAUCHY
= 2;
36 const sal_Int64 DIST_BERNOULLI
= 3;
37 const sal_Int64 DIST_BINOMIAL
= 4;
38 const sal_Int64 DIST_CHI_SQUARED
= 5;
39 const sal_Int64 DIST_GEOMETRIC
= 6;
40 const sal_Int64 DIST_NEGATIVE_BINOMIAL
= 7;
41 const sal_Int64 DIST_UNIFORM_INTEGER
= 8;
43 const sal_Int64 PERCISION
= 10000;
44 const sal_Int64 DIGITS
= 4;
48 ScRandomNumberGeneratorDialog::ScRandomNumberGeneratorDialog(
49 SfxBindings
* pSfxBindings
, SfxChildWindow
* pChildWindow
,
50 vcl::Window
* pParent
, ScViewData
* pViewData
) :
51 ScAnyRefDlg ( pSfxBindings
, pChildWindow
, pParent
,
52 "RandomNumberGeneratorDialog", "modules/scalc/ui/randomnumbergenerator.ui" ),
53 mpViewData ( pViewData
),
54 mpDoc( pViewData
->GetDocument() ),
55 mbDialogLostFocus( false )
57 get(mpInputRangeText
, "cell-range-label");
58 get(mpInputRangeEdit
, "cell-range-edit");
59 get(mpInputRangeButton
, "cell-range-button");
60 mpInputRangeEdit
->SetReferences(this, mpInputRangeText
);
61 mpInputRangeButton
->SetReferences(this, mpInputRangeEdit
);
63 get(mpParameter1Value
, "parameter1-spin");
64 get(mpParameter1Text
, "parameter1-label");
65 get(mpParameter2Value
, "parameter2-spin");
66 get(mpParameter2Text
, "parameter2-label");
68 get(mpEnableSeed
, "enable-seed-check");
69 get(mpSeed
, "seed-spin");
71 get(mpEnableRounding
, "enable-rounding-check");
72 get(mpDecimalPlaces
, "decimal-places-spin");
74 get(mpDistributionCombo
, "distribution-combo");
76 get(mpButtonOk
, "ok");
77 get(mpButtonApply
, "apply");
78 get(mpButtonClose
, "close");
81 GetRangeFromSelection();
84 ScRandomNumberGeneratorDialog::~ScRandomNumberGeneratorDialog()
89 void ScRandomNumberGeneratorDialog::dispose()
91 mpInputRangeText
.clear();
92 mpInputRangeEdit
.clear();
93 mpInputRangeButton
.clear();
94 mpDistributionCombo
.clear();
95 mpParameter1Text
.clear();
96 mpParameter1Value
.clear();
97 mpParameter2Text
.clear();
98 mpParameter2Value
.clear();
100 mpEnableSeed
.clear();
101 mpDecimalPlaces
.clear();
102 mpEnableRounding
.clear();
103 mpButtonApply
.clear();
105 mpButtonClose
.clear();
106 ScAnyRefDlg::dispose();
109 void ScRandomNumberGeneratorDialog::Init()
111 mpButtonOk
->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog
, OkClicked
) );
112 mpButtonClose
->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog
, CloseClicked
) );
113 mpButtonApply
->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog
, ApplyClicked
) );
115 Link
<> aLink
= LINK( this, ScRandomNumberGeneratorDialog
, GetFocusHandler
);
116 mpInputRangeEdit
->SetGetFocusHdl( aLink
);
117 mpInputRangeButton
->SetGetFocusHdl( aLink
);
119 aLink
= LINK( this, ScRandomNumberGeneratorDialog
, LoseFocusHandler
);
120 mpInputRangeEdit
->SetLoseFocusHdl ( aLink
);
121 mpInputRangeButton
->SetLoseFocusHdl ( aLink
);
123 mpInputRangeEdit
->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog
, InputRangeModified
));
124 mpParameter1Value
->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog
, Parameter1ValueModified
));
125 mpParameter2Value
->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog
, Parameter2ValueModified
));
127 mpDistributionCombo
->SetSelectHdl( LINK( this, ScRandomNumberGeneratorDialog
, DistributionChanged
));
129 mpEnableSeed
->SetToggleHdl( LINK( this, ScRandomNumberGeneratorDialog
, CheckChanged
));
130 mpEnableRounding
->SetToggleHdl( LINK( this, ScRandomNumberGeneratorDialog
, CheckChanged
));
132 DistributionChanged(NULL
);
136 void ScRandomNumberGeneratorDialog::GetRangeFromSelection()
138 mpViewData
->GetSimpleArea(maInputRange
);
139 OUString
aCurrentString(maInputRange
.Format(SCR_ABS_3D
, mpDoc
, mpDoc
->GetAddressConvention()));
140 mpInputRangeEdit
->SetText( aCurrentString
);
143 void ScRandomNumberGeneratorDialog::SetActive()
145 if ( mbDialogLostFocus
)
147 mbDialogLostFocus
= false;
148 if( mpInputRangeEdit
)
149 mpInputRangeEdit
->GrabFocus();
158 bool ScRandomNumberGeneratorDialog::Close()
160 return DoClose( ScRandomNumberGeneratorDialogWrapper::GetChildWindowId() );
163 void ScRandomNumberGeneratorDialog::SetReference( const ScRange
& rReferenceRange
, ScDocument
* pDoc
)
165 if ( mpInputRangeEdit
->IsEnabled() )
167 if ( rReferenceRange
.aStart
!= rReferenceRange
.aEnd
)
168 RefInputStart( mpInputRangeEdit
);
170 maInputRange
= rReferenceRange
;
172 OUString
aReferenceString(maInputRange
.Format(SCR_ABS_3D
, pDoc
, pDoc
->GetAddressConvention()));
173 mpInputRangeEdit
->SetRefString( aReferenceString
);
175 mpButtonApply
->Enable();
176 mpButtonOk
->Enable();
180 void ScRandomNumberGeneratorDialog::SelectGeneratorAndGenerateNumbers()
182 if (!maInputRange
.IsValid())
185 sal_Int16 aSelectedIndex
= mpDistributionCombo
-> GetSelectEntryPos();
186 sal_Int64 aSelectedId
= reinterpret_cast<sal_Int64
>(mpDistributionCombo
->GetEntryData(aSelectedIndex
));
188 sal_uInt32 seedValue
;
190 if( mpEnableSeed
->IsChecked() )
192 seedValue
= mpSeed
->GetValue();
197 osl_getSystemTime(&now
);
198 seedValue
= now
.Nanosec
;
201 std::mt19937
seed(seedValue
);
203 sal_Int64 parameterInteger1
= mpParameter1Value
->GetValue();
204 sal_Int64 parameterInteger2
= mpParameter2Value
->GetValue();
206 double parameter1
= parameterInteger1
/ static_cast<double>(PERCISION
);
207 double parameter2
= parameterInteger2
/ static_cast<double>(PERCISION
);
209 boost::optional
<sal_Int8
> aDecimalPlaces
;
210 if (mpEnableRounding
->IsChecked())
212 aDecimalPlaces
= static_cast<sal_Int8
>(mpDecimalPlaces
->GetValue());
219 std::uniform_real_distribution
<> distribution(parameter1
, parameter2
);
220 auto rng
= std::bind(distribution
, seed
);
221 GenerateNumbers(rng
, STR_DISTRIBUTION_UNIFORM_REAL
, aDecimalPlaces
);
224 case DIST_UNIFORM_INTEGER
:
226 std::uniform_int_distribution
<> distribution(parameterInteger1
, parameterInteger2
);
227 auto rng
= std::bind(distribution
, seed
);
228 GenerateNumbers(rng
, STR_DISTRIBUTION_UNIFORM_INTEGER
, aDecimalPlaces
);
233 std::normal_distribution
<> distribution(parameter1
, parameter2
);
234 auto rng
= std::bind(distribution
, seed
);
235 GenerateNumbers(rng
, STR_DISTRIBUTION_NORMAL
, aDecimalPlaces
);
240 std::cauchy_distribution
<> distribution(parameter1
);
241 auto rng
= std::bind(distribution
, seed
);
242 GenerateNumbers(rng
, STR_DISTRIBUTION_CAUCHY
, aDecimalPlaces
);
247 std::bernoulli_distribution
distribution(parameter1
);
248 auto rng
= std::bind(distribution
, seed
);
249 GenerateNumbers(rng
, STR_DISTRIBUTION_BERNOULLI
, aDecimalPlaces
);
254 std::binomial_distribution
<> distribution(parameterInteger2
, parameter1
);
255 auto rng
= std::bind(distribution
, seed
);
256 GenerateNumbers(rng
, STR_DISTRIBUTION_BINOMIAL
, aDecimalPlaces
);
259 case DIST_NEGATIVE_BINOMIAL
:
261 std::negative_binomial_distribution
<> distribution(parameterInteger2
, parameter1
);
262 auto rng
= std::bind(distribution
, seed
);
263 GenerateNumbers(rng
, STR_DISTRIBUTION_NEGATIVE_BINOMIAL
, aDecimalPlaces
);
266 case DIST_CHI_SQUARED
:
268 std::chi_squared_distribution
<> distribution(parameter1
);
269 auto rng
= std::bind(distribution
, seed
);
270 GenerateNumbers(rng
, STR_DISTRIBUTION_CHI_SQUARED
, aDecimalPlaces
);
275 std::geometric_distribution
<> distribution(parameter1
);
276 auto rng
= std::bind(distribution
, seed
);
277 GenerateNumbers(rng
, STR_DISTRIBUTION_GEOMETRIC
, aDecimalPlaces
);
284 void ScRandomNumberGeneratorDialog::GenerateNumbers(RNG
& randomGenerator
, const sal_Int16 aDistributionStringId
, boost::optional
<sal_Int8
> aDecimalPlaces
)
286 OUString aUndo
= SC_STRLOAD(RID_STATISTICS_DLGS
, STR_UNDO_DISTRIBUTION_TEMPLATE
);
287 OUString aDistributionName
= SC_STRLOAD(RID_STATISTICS_DLGS
, aDistributionStringId
);
288 aUndo
= aUndo
.replaceAll("$(DISTRIBUTION)", aDistributionName
);
290 ScDocShell
* pDocShell
= mpViewData
->GetDocShell();
291 svl::IUndoManager
* pUndoManager
= pDocShell
->GetUndoManager();
292 pUndoManager
->EnterListAction( aUndo
, aUndo
);
294 SCROW nRowStart
= maInputRange
.aStart
.Row();
295 SCROW nRowEnd
= maInputRange
.aEnd
.Row();
296 SCCOL nColStart
= maInputRange
.aStart
.Col();
297 SCCOL nColEnd
= maInputRange
.aEnd
.Col();
298 SCTAB nTabStart
= maInputRange
.aStart
.Tab();
299 SCTAB nTabEnd
= maInputRange
.aEnd
.Tab();
301 std::vector
<double> aVals
;
302 aVals
.reserve(nRowEnd
- nRowStart
+ 1);
304 for (SCROW nTab
= nTabStart
; nTab
<= nTabEnd
; ++nTab
)
306 for (SCCOL nCol
= nColStart
; nCol
<= nColEnd
; ++nCol
)
310 ScAddress
aPos(nCol
, nRowStart
, nTab
);
311 for (SCROW nRow
= nRowStart
; nRow
<= nRowEnd
; ++nRow
)
315 aVals
.push_back(rtl::math::round(randomGenerator(), *aDecimalPlaces
));
317 aVals
.push_back(randomGenerator());
320 pDocShell
->GetDocFunc().SetValueCells(aPos
, aVals
, true);
324 pUndoManager
->LeaveListAction();
326 pDocShell
->PostPaint( maInputRange
, PAINT_GRID
);
329 IMPL_LINK( ScRandomNumberGeneratorDialog
, OkClicked
, PushButton
*, /*pButton*/ )
336 IMPL_LINK( ScRandomNumberGeneratorDialog
, ApplyClicked
, PushButton
*, /*pButton*/ )
338 SelectGeneratorAndGenerateNumbers();
342 IMPL_LINK( ScRandomNumberGeneratorDialog
, CloseClicked
, PushButton
*, /*pButton*/ )
348 IMPL_LINK( ScRandomNumberGeneratorDialog
, GetFocusHandler
, Control
*, pCtrl
)
352 if( (pCtrl
== (Control
*) mpInputRangeEdit
) || (pCtrl
== (Control
*) mpInputRangeButton
) )
353 pEdit
= mpInputRangeEdit
;
356 pEdit
->SetSelection( Selection( 0, SELECTION_MAX
) );
361 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog
, LoseFocusHandler
)
363 mbDialogLostFocus
= !IsActive();
367 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog
, InputRangeModified
)
369 ScRangeList aRangeList
;
370 bool bValid
= ParseWithNames( aRangeList
, mpInputRangeEdit
->GetText(), mpDoc
);
371 const ScRange
* pRange
= (bValid
&& aRangeList
.size() == 1) ? aRangeList
[0] : nullptr;
374 maInputRange
= *pRange
;
375 mpButtonApply
->Enable();
376 mpButtonOk
->Enable();
377 // Highlight the resulting range.
378 mpInputRangeEdit
->StartUpdateData();
382 maInputRange
= ScRange( ScAddress::INITIALIZE_INVALID
);
383 mpButtonApply
->Disable();
384 mpButtonOk
->Disable();
389 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog
, Parameter1ValueModified
)
391 sal_Int16 aSelectedIndex
= mpDistributionCombo
-> GetSelectEntryPos();
392 sal_Int64 aSelectedId
= reinterpret_cast<sal_Int64
>( mpDistributionCombo
->GetEntryData(aSelectedIndex
) );
393 if (aSelectedId
== DIST_UNIFORM
||
394 aSelectedId
== DIST_UNIFORM_INTEGER
)
396 sal_Int64 min
= mpParameter1Value
->GetValue();
397 sal_Int64 max
= mpParameter2Value
->GetValue();
400 mpParameter2Value
->SetValue(min
);
406 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog
, Parameter2ValueModified
)
408 sal_Int16 aSelectedIndex
= mpDistributionCombo
-> GetSelectEntryPos();
409 sal_Int64 aSelectedId
= reinterpret_cast<sal_Int64
>( mpDistributionCombo
->GetEntryData(aSelectedIndex
) );
410 if (aSelectedId
== DIST_UNIFORM
||
411 aSelectedId
== DIST_UNIFORM_INTEGER
)
413 sal_Int64 min
= mpParameter1Value
->GetValue();
414 sal_Int64 max
= mpParameter2Value
->GetValue();
417 mpParameter1Value
->SetValue(max
);
423 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog
, CheckChanged
)
425 mpSeed
->Enable(mpEnableSeed
->IsChecked());
426 mpDecimalPlaces
->Enable(mpEnableRounding
->IsChecked());
430 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog
, DistributionChanged
)
432 sal_Int16 aSelectedIndex
= mpDistributionCombo
-> GetSelectEntryPos();
433 sal_Int64 aSelectedId
= reinterpret_cast<sal_Int64
>( mpDistributionCombo
->GetEntryData(aSelectedIndex
) );
435 mpParameter1Value
->SetMin(SAL_MIN_INT64
);
436 mpParameter1Value
->SetMax(SAL_MAX_INT64
);
437 mpParameter2Value
->SetMin(SAL_MIN_INT64
);
438 mpParameter2Value
->SetMax(SAL_MAX_INT64
);
440 mpParameter1Value
->SetDecimalDigits(DIGITS
);
441 mpParameter1Value
->SetSpinSize(PERCISION
);
443 mpParameter2Value
->SetDecimalDigits(DIGITS
);
444 mpParameter2Value
->SetSpinSize(PERCISION
);
450 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_MINIMUM
));
451 mpParameter2Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_MAXIMUM
));
452 mpParameter2Text
->Show();
453 mpParameter2Value
->Show();
456 case DIST_UNIFORM_INTEGER
:
458 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_MINIMUM
));
459 mpParameter1Value
->SetDecimalDigits(0);
460 mpParameter1Value
->SetSpinSize(1);
462 mpParameter2Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_MAXIMUM
));
463 mpParameter2Value
->SetDecimalDigits(0);
464 mpParameter2Value
->SetSpinSize(1);
466 mpParameter2Text
->Show();
467 mpParameter2Value
->Show();
472 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_MEAN
));
473 mpParameter2Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_DEVIATION
));
474 mpParameter2Text
->Show();
475 mpParameter2Value
->Show();
480 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_MEDIAN
));
481 mpParameter2Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_SIGMA
));
482 mpParameter2Text
->Show();
483 mpParameter2Value
->Show();
489 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_PROBABILITY
));
490 mpParameter1Value
->SetMin( 0 );
491 mpParameter1Value
->SetMax( PERCISION
);
492 mpParameter1Value
->SetSpinSize(1000);
494 mpParameter2Text
->Hide();
495 mpParameter2Value
->Hide();
499 case DIST_NEGATIVE_BINOMIAL
:
501 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_PROBABILITY
));
502 mpParameter1Value
->SetMin( 0 );
503 mpParameter1Value
->SetMax( PERCISION
);
504 mpParameter1Value
->SetSpinSize(1000);
506 mpParameter2Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_NUMBER_OF_TRIALS
));
507 mpParameter2Value
->SetDecimalDigits(0);
508 mpParameter2Value
->SetSpinSize(1);
509 mpParameter2Value
->SetMin(0);
511 mpParameter2Text
->Show();
512 mpParameter2Value
->Show();
515 case DIST_CHI_SQUARED
:
517 mpParameter1Text
->SetText( SC_STRLOAD( RID_STATISTICS_DLGS
, STR_RNG_PARAMETER_STANDARD_NU_VALUE
));
519 mpParameter2Text
->Hide();
520 mpParameter2Value
->Hide();
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */