Line data Source code
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 : */
10 :
11 : #include <sfx2/dispatch.hxx>
12 : #include <svl/zforlist.hxx>
13 : #include <svl/undo.hxx>
14 : #include <rtl/math.hxx>
15 :
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"
25 :
26 : #include <random>
27 :
28 : #include "RandomNumberGeneratorDialog.hxx"
29 :
30 : namespace
31 : {
32 :
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;
42 :
43 : const sal_Int64 PERCISION = 10000;
44 : const sal_Int64 DIGITS = 4;
45 :
46 : }
47 :
48 0 : 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 0 : mpDoc( pViewData->GetDocument() ),
55 0 : mbDialogLostFocus( false )
56 : {
57 0 : get(mpInputRangeText, "cell-range-label");
58 0 : get(mpInputRangeEdit, "cell-range-edit");
59 0 : get(mpInputRangeButton, "cell-range-button");
60 0 : mpInputRangeEdit->SetReferences(this, mpInputRangeText);
61 0 : mpInputRangeButton->SetReferences(this, mpInputRangeEdit);
62 :
63 0 : get(mpParameter1Value, "parameter1-spin");
64 0 : get(mpParameter1Text, "parameter1-label");
65 0 : get(mpParameter2Value, "parameter2-spin");
66 0 : get(mpParameter2Text, "parameter2-label");
67 :
68 0 : get(mpEnableSeed, "enable-seed-check");
69 0 : get(mpSeed, "seed-spin");
70 :
71 0 : get(mpEnableRounding, "enable-rounding-check");
72 0 : get(mpDecimalPlaces, "decimal-places-spin");
73 :
74 0 : get(mpDistributionCombo, "distribution-combo");
75 :
76 0 : get(mpButtonOk, "ok");
77 0 : get(mpButtonApply, "apply");
78 0 : get(mpButtonClose, "close");
79 :
80 0 : Init();
81 0 : GetRangeFromSelection();
82 0 : }
83 :
84 0 : ScRandomNumberGeneratorDialog::~ScRandomNumberGeneratorDialog()
85 : {
86 0 : disposeOnce();
87 0 : }
88 :
89 0 : void ScRandomNumberGeneratorDialog::dispose()
90 : {
91 0 : mpInputRangeText.clear();
92 0 : mpInputRangeEdit.clear();
93 0 : mpInputRangeButton.clear();
94 0 : mpDistributionCombo.clear();
95 0 : mpParameter1Text.clear();
96 0 : mpParameter1Value.clear();
97 0 : mpParameter2Text.clear();
98 0 : mpParameter2Value.clear();
99 0 : mpSeed.clear();
100 0 : mpEnableSeed.clear();
101 0 : mpDecimalPlaces.clear();
102 0 : mpEnableRounding.clear();
103 0 : mpButtonApply.clear();
104 0 : mpButtonOk.clear();
105 0 : mpButtonClose.clear();
106 0 : ScAnyRefDlg::dispose();
107 0 : }
108 :
109 0 : void ScRandomNumberGeneratorDialog::Init()
110 : {
111 0 : mpButtonOk->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog, OkClicked ) );
112 0 : mpButtonClose->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog, CloseClicked ) );
113 0 : mpButtonApply->SetClickHdl( LINK( this, ScRandomNumberGeneratorDialog, ApplyClicked ) );
114 :
115 0 : Link<> aLink = LINK( this, ScRandomNumberGeneratorDialog, GetFocusHandler );
116 0 : mpInputRangeEdit->SetGetFocusHdl( aLink );
117 0 : mpInputRangeButton->SetGetFocusHdl( aLink );
118 :
119 0 : aLink = LINK( this, ScRandomNumberGeneratorDialog, LoseFocusHandler );
120 0 : mpInputRangeEdit->SetLoseFocusHdl ( aLink );
121 0 : mpInputRangeButton->SetLoseFocusHdl ( aLink );
122 :
123 0 : mpParameter1Value->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog, Parameter1ValueModified ));
124 0 : mpParameter2Value->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog, Parameter2ValueModified ));
125 :
126 0 : mpDistributionCombo->SetSelectHdl( LINK( this, ScRandomNumberGeneratorDialog, DistributionChanged ));
127 :
128 0 : mpEnableSeed->SetToggleHdl( LINK( this, ScRandomNumberGeneratorDialog, CheckChanged ));
129 0 : mpEnableRounding->SetToggleHdl( LINK( this, ScRandomNumberGeneratorDialog, CheckChanged ));
130 :
131 0 : DistributionChanged(NULL);
132 0 : CheckChanged(NULL);
133 0 : }
134 :
135 0 : void ScRandomNumberGeneratorDialog::GetRangeFromSelection()
136 : {
137 0 : mpViewData->GetSimpleArea(maInputRange);
138 0 : OUString aCurrentString(maInputRange.Format(SCR_ABS_3D, mpDoc, mpDoc->GetAddressConvention()));
139 0 : mpInputRangeEdit->SetText( aCurrentString );
140 0 : }
141 :
142 0 : void ScRandomNumberGeneratorDialog::SetActive()
143 : {
144 0 : if ( mbDialogLostFocus )
145 : {
146 0 : mbDialogLostFocus = false;
147 0 : if( mpInputRangeEdit )
148 0 : mpInputRangeEdit->GrabFocus();
149 : }
150 : else
151 : {
152 0 : GrabFocus();
153 : }
154 0 : RefInputDone();
155 0 : }
156 :
157 0 : bool ScRandomNumberGeneratorDialog::Close()
158 : {
159 0 : return DoClose( ScRandomNumberGeneratorDialogWrapper::GetChildWindowId() );
160 : }
161 :
162 0 : void ScRandomNumberGeneratorDialog::SetReference( const ScRange& rReferenceRange, ScDocument* pDoc )
163 : {
164 0 : if ( mpInputRangeEdit->IsEnabled() )
165 : {
166 0 : if ( rReferenceRange.aStart != rReferenceRange.aEnd )
167 0 : RefInputStart( mpInputRangeEdit );
168 :
169 0 : maInputRange = rReferenceRange;
170 :
171 0 : OUString aReferenceString(maInputRange.Format(SCR_ABS_3D, pDoc, pDoc->GetAddressConvention()));
172 0 : mpInputRangeEdit->SetRefString( aReferenceString );
173 : }
174 0 : }
175 :
176 0 : void ScRandomNumberGeneratorDialog::SelectGeneratorAndGenerateNumbers()
177 : {
178 0 : sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
179 0 : sal_Int64 aSelectedId = reinterpret_cast<sal_Int64>(mpDistributionCombo->GetEntryData(aSelectedIndex));
180 :
181 : sal_uInt32 seedValue;
182 :
183 0 : if( mpEnableSeed->IsChecked() )
184 : {
185 0 : seedValue = mpSeed->GetValue();
186 : }
187 : else
188 : {
189 : TimeValue now;
190 0 : osl_getSystemTime(&now);
191 0 : seedValue = now.Nanosec;
192 : }
193 :
194 0 : std::mt19937 seed(seedValue);
195 :
196 0 : sal_Int64 parameterInteger1 = mpParameter1Value->GetValue();
197 0 : sal_Int64 parameterInteger2 = mpParameter2Value->GetValue();
198 :
199 0 : double parameter1 = parameterInteger1 / static_cast<double>(PERCISION);
200 0 : double parameter2 = parameterInteger2 / static_cast<double>(PERCISION);
201 :
202 0 : boost::optional<sal_Int8> aDecimalPlaces;
203 0 : if (mpEnableRounding->IsChecked())
204 : {
205 0 : aDecimalPlaces = static_cast<sal_Int8>(mpDecimalPlaces->GetValue());
206 : }
207 :
208 0 : switch(aSelectedId)
209 : {
210 : case DIST_UNIFORM:
211 : {
212 0 : std::uniform_real_distribution<> distribution(parameter1, parameter2);
213 0 : auto rng = std::bind(distribution, seed);
214 0 : GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_REAL, aDecimalPlaces);
215 0 : break;
216 : }
217 : case DIST_UNIFORM_INTEGER:
218 : {
219 0 : std::uniform_int_distribution<> distribution(parameterInteger1, parameterInteger2);
220 0 : auto rng = std::bind(distribution, seed);
221 0 : GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_INTEGER, aDecimalPlaces);
222 0 : break;
223 : }
224 : case DIST_NORMAL:
225 : {
226 0 : std::normal_distribution<> distribution(parameter1, parameter2);
227 0 : auto rng = std::bind(distribution, seed);
228 0 : GenerateNumbers(rng, STR_DISTRIBUTION_NORMAL, aDecimalPlaces);
229 0 : break;
230 : }
231 : case DIST_CAUCHY:
232 : {
233 0 : std::cauchy_distribution<> distribution(parameter1);
234 0 : auto rng = std::bind(distribution, seed);
235 0 : GenerateNumbers(rng, STR_DISTRIBUTION_CAUCHY, aDecimalPlaces);
236 0 : break;
237 : }
238 : case DIST_BERNOULLI:
239 : {
240 0 : std::bernoulli_distribution distribution(parameter1);
241 0 : auto rng = std::bind(distribution, seed);
242 0 : GenerateNumbers(rng, STR_DISTRIBUTION_BERNOULLI, aDecimalPlaces);
243 0 : break;
244 : }
245 : case DIST_BINOMIAL:
246 : {
247 0 : std::binomial_distribution<> distribution(parameterInteger2, parameter1);
248 0 : auto rng = std::bind(distribution, seed);
249 0 : GenerateNumbers(rng, STR_DISTRIBUTION_BINOMIAL, aDecimalPlaces);
250 0 : break;
251 : }
252 : case DIST_NEGATIVE_BINOMIAL:
253 : {
254 0 : std::negative_binomial_distribution<> distribution(parameterInteger2, parameter1);
255 0 : auto rng = std::bind(distribution, seed);
256 0 : GenerateNumbers(rng, STR_DISTRIBUTION_NEGATIVE_BINOMIAL, aDecimalPlaces);
257 0 : break;
258 : }
259 : case DIST_CHI_SQUARED:
260 : {
261 0 : std::chi_squared_distribution<> distribution(parameter1);
262 0 : auto rng = std::bind(distribution, seed);
263 0 : GenerateNumbers(rng, STR_DISTRIBUTION_CHI_SQUARED, aDecimalPlaces);
264 0 : break;
265 : }
266 : case DIST_GEOMETRIC:
267 : {
268 0 : std::geometric_distribution<> distribution(parameter1);
269 0 : auto rng = std::bind(distribution, seed);
270 0 : GenerateNumbers(rng, STR_DISTRIBUTION_GEOMETRIC, aDecimalPlaces);
271 0 : break;
272 : }
273 0 : }
274 0 : }
275 :
276 : template<class RNG>
277 0 : void ScRandomNumberGeneratorDialog::GenerateNumbers(RNG& randomGenerator, const sal_Int16 aDistributionStringId, boost::optional<sal_Int8> aDecimalPlaces)
278 : {
279 0 : OUString aUndo = SC_STRLOAD(RID_STATISTICS_DLGS, STR_UNDO_DISTRIBUTION_TEMPLATE);
280 0 : OUString aDistributionName = SC_STRLOAD(RID_STATISTICS_DLGS, aDistributionStringId);
281 0 : aUndo = aUndo.replaceAll("$(DISTRIBUTION)", aDistributionName);
282 :
283 0 : ScDocShell* pDocShell = mpViewData->GetDocShell();
284 0 : svl::IUndoManager* pUndoManager = pDocShell->GetUndoManager();
285 0 : pUndoManager->EnterListAction( aUndo, aUndo );
286 :
287 0 : SCROW nRowStart = maInputRange.aStart.Row();
288 0 : SCROW nRowEnd = maInputRange.aEnd.Row();
289 0 : SCCOL nColStart = maInputRange.aStart.Col();
290 0 : SCCOL nColEnd = maInputRange.aEnd.Col();
291 0 : SCTAB nTabStart = maInputRange.aStart.Tab();
292 0 : SCTAB nTabEnd = maInputRange.aEnd.Tab();
293 :
294 0 : std::vector<double> aVals;
295 0 : aVals.reserve(nRowEnd - nRowStart + 1);
296 :
297 0 : for (SCROW nTab = nTabStart; nTab <= nTabEnd; ++nTab)
298 : {
299 0 : for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
300 : {
301 0 : aVals.clear();
302 :
303 0 : ScAddress aPos(nCol, nRowStart, nTab);
304 0 : for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
305 : {
306 :
307 0 : if (aDecimalPlaces)
308 0 : aVals.push_back(rtl::math::round(randomGenerator(), *aDecimalPlaces));
309 : else
310 0 : aVals.push_back(randomGenerator());
311 : }
312 :
313 0 : pDocShell->GetDocFunc().SetValueCells(aPos, aVals, true);
314 : }
315 : }
316 :
317 0 : pUndoManager->LeaveListAction();
318 :
319 0 : pDocShell->PostPaint( maInputRange, PAINT_GRID );
320 0 : }
321 :
322 0 : IMPL_LINK( ScRandomNumberGeneratorDialog, OkClicked, PushButton*, /*pButton*/ )
323 : {
324 0 : ApplyClicked(NULL);
325 0 : CloseClicked(NULL);
326 0 : return 0;
327 : }
328 :
329 0 : IMPL_LINK( ScRandomNumberGeneratorDialog, ApplyClicked, PushButton*, /*pButton*/ )
330 : {
331 0 : SelectGeneratorAndGenerateNumbers();
332 0 : return 0;
333 : }
334 :
335 0 : IMPL_LINK( ScRandomNumberGeneratorDialog, CloseClicked, PushButton*, /*pButton*/ )
336 : {
337 0 : Close();
338 0 : return 0;
339 : }
340 :
341 0 : IMPL_LINK( ScRandomNumberGeneratorDialog, GetFocusHandler, Control*, pCtrl )
342 : {
343 0 : Edit* pEdit = NULL;
344 :
345 0 : if( (pCtrl == static_cast<Control*>(mpInputRangeEdit)) || (pCtrl == static_cast<Control*>(mpInputRangeButton)) )
346 0 : pEdit = mpInputRangeEdit;
347 :
348 0 : if( pEdit )
349 0 : pEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
350 :
351 0 : return 0;
352 : }
353 :
354 0 : IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, LoseFocusHandler)
355 : {
356 0 : mbDialogLostFocus = !IsActive();
357 0 : return 0;
358 : }
359 :
360 0 : IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, Parameter1ValueModified)
361 : {
362 0 : sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
363 0 : sal_Int64 aSelectedId = reinterpret_cast<sal_Int64>( mpDistributionCombo->GetEntryData(aSelectedIndex) );
364 0 : if (aSelectedId == DIST_UNIFORM ||
365 : aSelectedId == DIST_UNIFORM_INTEGER)
366 : {
367 0 : sal_Int64 min = mpParameter1Value->GetValue();
368 0 : sal_Int64 max = mpParameter2Value->GetValue();
369 0 : if(min > max)
370 : {
371 0 : mpParameter2Value->SetValue(min);
372 : }
373 : }
374 0 : return 0;
375 : }
376 :
377 0 : IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, Parameter2ValueModified)
378 : {
379 0 : sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
380 0 : sal_Int64 aSelectedId = reinterpret_cast<sal_Int64>( mpDistributionCombo->GetEntryData(aSelectedIndex) );
381 0 : if (aSelectedId == DIST_UNIFORM ||
382 : aSelectedId == DIST_UNIFORM_INTEGER)
383 : {
384 0 : sal_Int64 min = mpParameter1Value->GetValue();
385 0 : sal_Int64 max = mpParameter2Value->GetValue();
386 0 : if(min > max)
387 : {
388 0 : mpParameter1Value->SetValue(max);
389 : }
390 : }
391 0 : return 0;
392 : }
393 :
394 0 : IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, CheckChanged)
395 : {
396 0 : mpSeed->Enable(mpEnableSeed->IsChecked());
397 0 : mpDecimalPlaces->Enable(mpEnableRounding->IsChecked());
398 0 : return 0;
399 : }
400 :
401 0 : IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, DistributionChanged)
402 : {
403 0 : sal_Int16 aSelectedIndex = mpDistributionCombo-> GetSelectEntryPos();
404 0 : sal_Int64 aSelectedId = reinterpret_cast<sal_Int64>( mpDistributionCombo->GetEntryData(aSelectedIndex) );
405 :
406 0 : mpParameter1Value->SetMin(SAL_MIN_INT64);
407 0 : mpParameter1Value->SetMax(SAL_MAX_INT64);
408 0 : mpParameter2Value->SetMin(SAL_MIN_INT64);
409 0 : mpParameter2Value->SetMax(SAL_MAX_INT64);
410 :
411 0 : mpParameter1Value->SetDecimalDigits(DIGITS);
412 0 : mpParameter1Value->SetSpinSize(PERCISION);
413 :
414 0 : mpParameter2Value->SetDecimalDigits(DIGITS);
415 0 : mpParameter2Value->SetSpinSize(PERCISION);
416 :
417 0 : switch(aSelectedId)
418 : {
419 : case DIST_UNIFORM:
420 : {
421 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MINIMUM));
422 0 : mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MAXIMUM));
423 0 : mpParameter2Text->Show();
424 0 : mpParameter2Value->Show();
425 0 : break;
426 : }
427 : case DIST_UNIFORM_INTEGER:
428 : {
429 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MINIMUM));
430 0 : mpParameter1Value->SetDecimalDigits(0);
431 0 : mpParameter1Value->SetSpinSize(1);
432 :
433 0 : mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MAXIMUM));
434 0 : mpParameter2Value->SetDecimalDigits(0);
435 0 : mpParameter2Value->SetSpinSize(1);
436 :
437 0 : mpParameter2Text->Show();
438 0 : mpParameter2Value->Show();
439 0 : break;
440 : }
441 : case DIST_NORMAL:
442 : {
443 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_MEAN));
444 0 : mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_DEVIATION));
445 0 : mpParameter2Text->Show();
446 0 : mpParameter2Value->Show();
447 0 : break;
448 : }
449 : case DIST_CAUCHY:
450 : {
451 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_MEDIAN));
452 0 : mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_SIGMA));
453 0 : mpParameter2Text->Show();
454 0 : mpParameter2Value->Show();
455 0 : break;
456 : }
457 : case DIST_BERNOULLI:
458 : case DIST_GEOMETRIC:
459 : {
460 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_PROBABILITY));
461 0 : mpParameter1Value->SetMin( 0 );
462 0 : mpParameter1Value->SetMax( PERCISION );
463 0 : mpParameter1Value->SetSpinSize(1000);
464 :
465 0 : mpParameter2Text->Hide();
466 0 : mpParameter2Value->Hide();
467 0 : break;
468 : }
469 : case DIST_BINOMIAL:
470 : case DIST_NEGATIVE_BINOMIAL:
471 : {
472 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_PROBABILITY));
473 0 : mpParameter1Value->SetMin( 0 );
474 0 : mpParameter1Value->SetMax( PERCISION );
475 0 : mpParameter1Value->SetSpinSize(1000);
476 :
477 0 : mpParameter2Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_NUMBER_OF_TRIALS));
478 0 : mpParameter2Value->SetDecimalDigits(0);
479 0 : mpParameter2Value->SetSpinSize(1);
480 0 : mpParameter2Value->SetMin(0);
481 :
482 0 : mpParameter2Text->Show();
483 0 : mpParameter2Value->Show();
484 0 : break;
485 : }
486 : case DIST_CHI_SQUARED:
487 : {
488 0 : mpParameter1Text->SetText( SC_STRLOAD( RID_STATISTICS_DLGS, STR_RNG_PARAMETER_STANDARD_NU_VALUE));
489 :
490 0 : mpParameter2Text->Hide();
491 0 : mpParameter2Value->Hide();
492 0 : break;
493 : }
494 : }
495 0 : return 0;
496 156 : }
497 :
498 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|