Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / StatisticsDialogs / RandomNumberGeneratorDialog.cxx
blob35b72f8aed2ae121e9c79cb618c3edd7efade4a3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
9 */
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"
18 #include "docsh.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"
26 #include <boost/random.hpp>
27 #include <boost/random/uniform_real_distribution.hpp>
28 #include <boost/random/uniform_int_distribution.hpp>
29 #include <boost/random/binomial_distribution.hpp>
30 #include <boost/random/normal_distribution.hpp>
31 #include <boost/random/cauchy_distribution.hpp>
32 #include <boost/random/bernoulli_distribution.hpp>
33 #include <boost/random/chi_squared_distribution.hpp>
34 #include <boost/random/geometric_distribution.hpp>
35 #include <boost/random/negative_binomial_distribution.hpp>
37 #include "RandomNumberGeneratorDialog.hxx"
39 namespace
42 const sal_Int64 DIST_UNIFORM = 0;
43 const sal_Int64 DIST_NORMAL = 1;
44 const sal_Int64 DIST_CAUCHY = 2;
45 const sal_Int64 DIST_BERNOULLI = 3;
46 const sal_Int64 DIST_BINOMIAL = 4;
47 const sal_Int64 DIST_CHI_SQUARED = 5;
48 const sal_Int64 DIST_GEOMETRIC = 6;
49 const sal_Int64 DIST_NEGATIVE_BINOMIAL = 7;
50 const sal_Int64 DIST_UNIFORM_INTEGER = 8;
52 const sal_Int64 PERCISION = 10000;
53 const sal_Int64 DIGITS = 4;
57 ScRandomNumberGeneratorDialog::ScRandomNumberGeneratorDialog(
58 SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
59 Window* pParent, ScViewData* pViewData ) :
60 ScAnyRefDlg ( pSfxBindings, pChildWindow, pParent,
61 "RandomNumberGeneratorDialog", "modules/scalc/ui/randomnumbergenerator.ui" ),
62 mpViewData ( pViewData ),
63 mpDoc( pViewData->GetDocument() ),
64 mbDialogLostFocus( false )
66 get(mpInputRangeText, "cell-range-label");
67 get(mpInputRangeEdit, "cell-range-edit");
68 get(mpInputRangeButton, "cell-range-button");
69 mpInputRangeEdit->SetReferences(this, mpInputRangeText);
70 mpInputRangeButton->SetReferences(this, mpInputRangeEdit);
72 get(mpParameter1Value, "parameter1-spin");
73 get(mpParameter1Text, "parameter1-label");
74 get(mpParameter2Value, "parameter2-spin");
75 get(mpParameter2Text, "parameter2-label");
77 get(mpEnableSeed, "enable-seed-check");
78 get(mpSeed, "seed-spin");
80 get(mpEnableRounding, "enable-rounding-check");
81 get(mpDecimalPlaces, "decimal-places-spin");
83 get(mpDistributionCombo, "distribution-combo");
85 get(mpButtonOk, "ok");
86 get(mpButtonApply, "apply");
87 get(mpButtonClose, "close");
89 Init();
90 GetRangeFromSelection();
93 void ScRandomNumberGeneratorDialog::Init()
95 mpButtonOk->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog, OkClicked ) );
96 mpButtonClose->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog, CloseClicked ) );
97 mpButtonApply->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog, ApplyClicked ) );
99 Link aLink = LINK( this, ScRandomNumberGeneratorDialog, GetFocusHandler );
100 mpInputRangeEdit->SetGetFocusHdl( aLink );
101 mpInputRangeButton->SetGetFocusHdl( aLink );
103 aLink = LINK( this, ScRandomNumberGeneratorDialog, LoseFocusHandler );
104 mpInputRangeEdit->SetLoseFocusHdl ( aLink );
105 mpInputRangeButton->SetLoseFocusHdl ( aLink );
107 mpParameter1Value->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog, Parameter1ValueModified ));
108 mpParameter2Value->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog, Parameter2ValueModified ));
110 mpDistributionCombo->SetSelectHdl( LINK( this, ScRandomNumberGeneratorDialog, DistributionChanged ));
112 mpEnableSeed->SetToggleHdl( LINK( this, ScRandomNumberGeneratorDialog, CheckChanged ));
113 mpEnableRounding->SetToggleHdl( LINK( this, ScRandomNumberGeneratorDialog, CheckChanged ));
115 DistributionChanged(NULL);
116 CheckChanged(NULL);
119 void ScRandomNumberGeneratorDialog::GetRangeFromSelection()
121 mpViewData->GetSimpleArea(maInputRange);
122 OUString aCurrentString(maInputRange.Format(SCR_ABS_3D, mpDoc, mpDoc->GetAddressConvention()));
123 mpInputRangeEdit->SetText( aCurrentString );
126 ScRandomNumberGeneratorDialog::~ScRandomNumberGeneratorDialog()
129 void ScRandomNumberGeneratorDialog::SetActive()
131 if ( mbDialogLostFocus )
133 mbDialogLostFocus = false;
134 if( mpInputRangeEdit )
135 mpInputRangeEdit->GrabFocus();
137 else
139 GrabFocus();
141 RefInputDone();
144 bool ScRandomNumberGeneratorDialog::Close()
146 return DoClose( ScRandomNumberGeneratorDialogWrapper::GetChildWindowId() );
149 void ScRandomNumberGeneratorDialog::SetReference( const ScRange& rReferenceRange, ScDocument* pDoc )
151 if ( mpInputRangeEdit->IsEnabled() )
153 if ( rReferenceRange.aStart != rReferenceRange.aEnd )
154 RefInputStart( mpInputRangeEdit );
156 maInputRange = rReferenceRange;
158 OUString aReferenceString(maInputRange.Format(SCR_ABS_3D, pDoc, pDoc->GetAddressConvention()));
159 mpInputRangeEdit->SetRefString( aReferenceString );
163 void ScRandomNumberGeneratorDialog::SelectGeneratorAndGenerateNumbers()
165 sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
166 sal_Int64 aSelectedId = (sal_Int64) mpDistributionCombo->GetEntryData(aSelectedIndex);
168 sal_uInt32 seedValue;
170 if( mpEnableSeed->IsChecked() )
172 seedValue = mpSeed->GetValue();
174 else
176 TimeValue now;
177 osl_getSystemTime(&now);
178 seedValue = now.Nanosec;
181 boost::mt19937 seed(seedValue);
183 sal_Int64 parameterInteger1 = mpParameter1Value->GetValue();
184 sal_Int64 parameterInteger2 = mpParameter2Value->GetValue();
186 double parameter1 = parameterInteger1 / static_cast<double>(PERCISION);
187 double parameter2 = parameterInteger2 / static_cast<double>(PERCISION);
189 boost::optional<sal_Int8> aDecimalPlaces;
190 if (mpEnableRounding->IsChecked())
192 aDecimalPlaces = static_cast<sal_Int8>(mpDecimalPlaces->GetValue());
195 switch(aSelectedId)
197 case DIST_UNIFORM:
199 boost::random::uniform_real_distribution<> distribution(parameter1, parameter2);
200 boost::variate_generator<boost::mt19937&, boost::random::uniform_real_distribution<> > rng(seed, distribution);
201 GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_REAL, aDecimalPlaces);
202 break;
204 case DIST_UNIFORM_INTEGER:
206 boost::random::uniform_int_distribution<> distribution(parameterInteger1, parameterInteger2);
207 boost::variate_generator<boost::mt19937&, boost::random::uniform_int_distribution<> > rng(seed, distribution);
208 GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_INTEGER, aDecimalPlaces);
209 break;
211 case DIST_NORMAL:
213 boost::random::normal_distribution<> distribution(parameter1, parameter2);
214 boost::variate_generator<boost::mt19937&, boost::random::normal_distribution<> > rng(seed, distribution);
215 GenerateNumbers(rng, STR_DISTRIBUTION_NORMAL, aDecimalPlaces);
216 break;
218 case DIST_CAUCHY:
220 boost::random::cauchy_distribution<> distribution(parameter1);
221 boost::variate_generator<boost::mt19937&, boost::random::cauchy_distribution<> > rng(seed, distribution);
222 GenerateNumbers(rng, STR_DISTRIBUTION_CAUCHY, aDecimalPlaces);
223 break;
225 case DIST_BERNOULLI:
227 boost::random::bernoulli_distribution<> distribution(parameter1);
228 boost::variate_generator<boost::mt19937&, boost::random::bernoulli_distribution<> > rng(seed, distribution);
229 GenerateNumbers(rng, STR_DISTRIBUTION_BERNOULLI, aDecimalPlaces);
230 break;
232 case DIST_BINOMIAL:
234 boost::random::binomial_distribution<> distribution(parameterInteger2, parameter1);
235 boost::variate_generator<boost::mt19937&, boost::random::binomial_distribution<> > rng(seed, distribution);
236 GenerateNumbers(rng, STR_DISTRIBUTION_BINOMIAL, aDecimalPlaces);
237 break;
239 case DIST_NEGATIVE_BINOMIAL:
241 boost::random::negative_binomial_distribution<> distribution(parameterInteger2, parameter1);
242 boost::variate_generator<boost::mt19937&, boost::random::negative_binomial_distribution<> > rng(seed, distribution);
243 GenerateNumbers(rng, STR_DISTRIBUTION_NEGATIVE_BINOMIAL, aDecimalPlaces);
244 break;
246 case DIST_CHI_SQUARED:
248 boost::random::chi_squared_distribution<> distribution(parameter1);
249 boost::variate_generator<boost::mt19937&, boost::random::chi_squared_distribution<> > rng(seed, distribution);
250 GenerateNumbers(rng, STR_DISTRIBUTION_CHI_SQUARED, aDecimalPlaces);
251 break;
253 case DIST_GEOMETRIC:
255 boost::random::geometric_distribution<> distribution(parameter1);
256 boost::variate_generator<boost::mt19937&, boost::random::geometric_distribution<> > rng(seed, distribution);
257 GenerateNumbers(rng, STR_DISTRIBUTION_GEOMETRIC, aDecimalPlaces);
258 break;
263 template<class RNG>
264 void ScRandomNumberGeneratorDialog::GenerateNumbers(RNG randomGenerator, const sal_Int16 aDistributionStringId, boost::optional<sal_Int8> aDecimalPlaces)
266 OUString aUndo = SC_STRLOAD(RID_STATISTICS_DLGS, STR_UNDO_DISTRIBUTION_TEMPLATE);
267 OUString aDistributionName = SC_STRLOAD(RID_STATISTICS_DLGS, aDistributionStringId);
268 aUndo = aUndo.replaceAll("$(DISTRIBUTION)", aDistributionName);
270 ScDocShell* pDocShell = mpViewData->GetDocShell();
271 svl::IUndoManager* pUndoManager = pDocShell->GetUndoManager();
272 pUndoManager->EnterListAction( aUndo, aUndo );
274 SCROW nRowStart = maInputRange.aStart.Row();
275 SCROW nRowEnd = maInputRange.aEnd.Row();
276 SCCOL nColStart = maInputRange.aStart.Col();
277 SCCOL nColEnd = maInputRange.aEnd.Col();
278 SCTAB nTabStart = maInputRange.aStart.Tab();
279 SCTAB nTabEnd = maInputRange.aEnd.Tab();
281 std::vector<double> aVals;
282 aVals.reserve(nRowEnd - nRowStart + 1);
284 for (SCROW nTab = nTabStart; nTab <= nTabEnd; ++nTab)
286 for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
288 aVals.clear();
290 ScAddress aPos(nCol, nRowStart, nTab);
291 for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
294 if (aDecimalPlaces)
295 aVals.push_back(rtl::math::round(randomGenerator(), *aDecimalPlaces));
296 else
297 aVals.push_back(randomGenerator());
300 pDocShell->GetDocFunc().SetValueCells(aPos, aVals, true);
304 pUndoManager->LeaveListAction();
306 pDocShell->PostPaint( maInputRange, PAINT_GRID );
309 IMPL_LINK( ScRandomNumberGeneratorDialog, OkClicked, PushButton*, /*pButton*/ )
311 ApplyClicked(NULL);
312 CloseClicked(NULL);
313 return 0;
317 IMPL_LINK( ScRandomNumberGeneratorDialog, ApplyClicked, PushButton*, /*pButton*/ )
319 SelectGeneratorAndGenerateNumbers();
320 return 0;
323 IMPL_LINK( ScRandomNumberGeneratorDialog, CloseClicked, PushButton*, /*pButton*/ )
325 Close();
326 return 0;
329 IMPL_LINK( ScRandomNumberGeneratorDialog, GetFocusHandler, Control*, pCtrl )
331 Edit* pEdit = NULL;
333 if( (pCtrl == (Control*) mpInputRangeEdit) || (pCtrl == (Control*) mpInputRangeButton) )
334 pEdit = mpInputRangeEdit;
336 if( pEdit )
337 pEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
339 return 0;
342 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, LoseFocusHandler)
344 mbDialogLostFocus = !IsActive();
345 return 0;
348 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, Parameter1ValueModified)
350 sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
351 sal_Int64 aSelectedId = (sal_Int64) mpDistributionCombo->GetEntryData(aSelectedIndex);
352 if (aSelectedId == DIST_UNIFORM ||
353 aSelectedId == DIST_UNIFORM_INTEGER)
355 sal_Int64 min = mpParameter1Value->GetValue();
356 sal_Int64 max = mpParameter2Value->GetValue();
357 if(min > max)
359 mpParameter2Value->SetValue(min);
362 return 0;
365 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, Parameter2ValueModified)
367 sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
368 sal_Int64 aSelectedId = (sal_Int64) mpDistributionCombo->GetEntryData(aSelectedIndex);
369 if (aSelectedId == DIST_UNIFORM ||
370 aSelectedId == DIST_UNIFORM_INTEGER)
372 sal_Int64 min = mpParameter1Value->GetValue();
373 sal_Int64 max = mpParameter2Value->GetValue();
374 if(min > max)
376 mpParameter1Value->SetValue(max);
379 return 0;
382 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, CheckChanged)
384 mpSeed->Enable(mpEnableSeed->IsChecked());
385 mpDecimalPlaces->Enable(mpEnableRounding->IsChecked());
386 return 0;
389 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, DistributionChanged)
391 sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
392 sal_Int64 aSelectedId = (sal_Int64) mpDistributionCombo->GetEntryData(aSelectedIndex);
394 mpParameter1Value->SetMin(SAL_MIN_INT64);
395 mpParameter1Value->SetMax(SAL_MAX_INT64);
396 mpParameter2Value->SetMin(SAL_MIN_INT64);
397 mpParameter2Value->SetMax(SAL_MAX_INT64);
399 mpParameter1Value->SetDecimalDigits(DIGITS);
400 mpParameter1Value->SetSpinSize(PERCISION);
402 mpParameter2Value->SetDecimalDigits(DIGITS);
403 mpParameter2Value->SetSpinSize(PERCISION);
405 switch(aSelectedId)
407 case DIST_UNIFORM:
409 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MINIMUM));
410 mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MAXIMUM));
411 mpParameter2Text->Show();
412 mpParameter2Value->Show();
413 break;
415 case DIST_UNIFORM_INTEGER:
417 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MINIMUM));
418 mpParameter1Value->SetDecimalDigits(0);
419 mpParameter1Value->SetSpinSize(1);
421 mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MAXIMUM));
422 mpParameter2Value->SetDecimalDigits(0);
423 mpParameter2Value->SetSpinSize(1);
425 mpParameter2Text->Show();
426 mpParameter2Value->Show();
427 break;
429 case DIST_NORMAL:
431 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MEAN));
432 mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_DEVIATION));
433 mpParameter2Text->Show();
434 mpParameter2Value->Show();
435 break;
437 case DIST_CAUCHY:
439 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_MEDIAN));
440 mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_SIGMA));
441 mpParameter2Text->Show();
442 mpParameter2Value->Show();
443 break;
445 case DIST_BERNOULLI:
446 case DIST_GEOMETRIC:
448 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_PROBABILITY));
449 mpParameter1Value->SetMin( 0 );
450 mpParameter1Value->SetMax( PERCISION );
451 mpParameter1Value->SetSpinSize(1000);
453 mpParameter2Text->Hide();
454 mpParameter2Value->Hide();
455 break;
457 case DIST_BINOMIAL:
458 case DIST_NEGATIVE_BINOMIAL:
460 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_PROBABILITY));
461 mpParameter1Value->SetMin( 0 );
462 mpParameter1Value->SetMax( PERCISION );
463 mpParameter1Value->SetSpinSize(1000);
465 mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_NUMBER_OF_TRIALS));
466 mpParameter2Value->SetDecimalDigits(0);
467 mpParameter2Value->SetSpinSize(1);
468 mpParameter2Value->SetMin(0);
470 mpParameter2Text->Show();
471 mpParameter2Value->Show();
472 break;
474 case DIST_CHI_SQUARED:
476 mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_NU_VALUE));
478 mpParameter2Text->Hide();
479 mpParameter2Value->Hide();
480 break;
483 return 0;
486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */