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