fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / StatisticsDialogs / RandomNumberGeneratorDialog.cxx
blobcefabf89d1aa4440d6499b6f3e55fc95be44711f
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 <random>
28 #include "RandomNumberGeneratorDialog.hxx"
30 namespace
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");
80 Init();
81 GetRangeFromSelection();
84 ScRandomNumberGeneratorDialog::~ScRandomNumberGeneratorDialog()
86 disposeOnce();
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();
99 mpSeed.clear();
100 mpEnableSeed.clear();
101 mpDecimalPlaces.clear();
102 mpEnableRounding.clear();
103 mpButtonApply.clear();
104 mpButtonOk.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);
133 CheckChanged(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();
151 else
153 GrabFocus();
155 RefInputDone();
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())
183 return;
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();
194 else
196 TimeValue now;
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());
215 switch(aSelectedId)
217 case DIST_UNIFORM:
219 std::uniform_real_distribution<> distribution(parameter1, parameter2);
220 auto rng = std::bind(distribution, seed);
221 GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_REAL, aDecimalPlaces);
222 break;
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);
229 break;
231 case DIST_NORMAL:
233 std::normal_distribution<> distribution(parameter1, parameter2);
234 auto rng = std::bind(distribution, seed);
235 GenerateNumbers(rng, STR_DISTRIBUTION_NORMAL, aDecimalPlaces);
236 break;
238 case DIST_CAUCHY:
240 std::cauchy_distribution<> distribution(parameter1);
241 auto rng = std::bind(distribution, seed);
242 GenerateNumbers(rng, STR_DISTRIBUTION_CAUCHY, aDecimalPlaces);
243 break;
245 case DIST_BERNOULLI:
247 std::bernoulli_distribution distribution(parameter1);
248 auto rng = std::bind(distribution, seed);
249 GenerateNumbers(rng, STR_DISTRIBUTION_BERNOULLI, aDecimalPlaces);
250 break;
252 case DIST_BINOMIAL:
254 std::binomial_distribution<> distribution(parameterInteger2, parameter1);
255 auto rng = std::bind(distribution, seed);
256 GenerateNumbers(rng, STR_DISTRIBUTION_BINOMIAL, aDecimalPlaces);
257 break;
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);
264 break;
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);
271 break;
273 case DIST_GEOMETRIC:
275 std::geometric_distribution<> distribution(parameter1);
276 auto rng = std::bind(distribution, seed);
277 GenerateNumbers(rng, STR_DISTRIBUTION_GEOMETRIC, aDecimalPlaces);
278 break;
283 template<class RNG>
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)
308 aVals.clear();
310 ScAddress aPos(nCol, nRowStart, nTab);
311 for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
314 if (aDecimalPlaces)
315 aVals.push_back(rtl::math::round(randomGenerator(), *aDecimalPlaces));
316 else
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*/ )
331 ApplyClicked(NULL);
332 CloseClicked(NULL);
333 return 0;
336 IMPL_LINK( ScRandomNumberGeneratorDialog, ApplyClicked, PushButton*, /*pButton*/ )
338 SelectGeneratorAndGenerateNumbers();
339 return 0;
342 IMPL_LINK( ScRandomNumberGeneratorDialog, CloseClicked, PushButton*, /*pButton*/ )
344 Close();
345 return 0;
348 IMPL_LINK( ScRandomNumberGeneratorDialog, GetFocusHandler, Control*, pCtrl )
350 Edit* pEdit = NULL;
352 if( (pCtrl == (Control*) mpInputRangeEdit) || (pCtrl == (Control*) mpInputRangeButton) )
353 pEdit = mpInputRangeEdit;
355 if( pEdit )
356 pEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
358 return 0;
361 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, LoseFocusHandler)
363 mbDialogLostFocus = !IsActive();
364 return 0;
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;
372 if (pRange)
374 maInputRange = *pRange;
375 mpButtonApply->Enable();
376 mpButtonOk->Enable();
377 // Highlight the resulting range.
378 mpInputRangeEdit->StartUpdateData();
380 else
382 maInputRange = ScRange( ScAddress::INITIALIZE_INVALID);
383 mpButtonApply->Disable();
384 mpButtonOk->Disable();
386 return 0;
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();
398 if(min > max)
400 mpParameter2Value->SetValue(min);
403 return 0;
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();
415 if(min > max)
417 mpParameter1Value->SetValue(max);
420 return 0;
423 IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, CheckChanged)
425 mpSeed->Enable(mpEnableSeed->IsChecked());
426 mpDecimalPlaces->Enable(mpEnableRounding->IsChecked());
427 return 0;
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);
446 switch(aSelectedId)
448 case DIST_UNIFORM:
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();
454 break;
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();
468 break;
470 case DIST_NORMAL:
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();
476 break;
478 case DIST_CAUCHY:
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();
484 break;
486 case DIST_BERNOULLI:
487 case DIST_GEOMETRIC:
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();
496 break;
498 case DIST_BINOMIAL:
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();
513 break;
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();
521 break;
524 return 0;
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */