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 :
15 : #include "rangelst.hxx"
16 : #include "scitems.hxx"
17 : #include "docsh.hxx"
18 : #include "document.hxx"
19 : #include "uiitems.hxx"
20 : #include "reffact.hxx"
21 : #include "strload.hxx"
22 : #include "random.hxx"
23 : #include "docfunc.hxx"
24 : #include "StatisticsDialogs.hrc"
25 :
26 : #include <boost/random.hpp>
27 :
28 : #include "SamplingDialog.hxx"
29 :
30 0 : ScSamplingDialog::ScSamplingDialog(
31 : SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
32 : Window* pParent, ScViewData* pViewData ) :
33 : ScAnyRefDlg ( pSfxBindings, pChildWindow, pParent,
34 : "SamplingDialog", "modules/scalc/ui/samplingdialog.ui" ),
35 : mViewData ( pViewData ),
36 0 : mDocument ( pViewData->GetDocument() ),
37 : mAddressDetails ( mDocument->GetAddressConvention(), 0, 0 ),
38 0 : mCurrentAddress ( pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo() ),
39 0 : mDialogLostFocus( false )
40 : {
41 0 : get(mpInputRangeLabel, "input-range-label");
42 0 : get(mpInputRangeEdit, "input-range-edit");
43 0 : get(mpInputRangeButton, "input-range-button");
44 0 : mpInputRangeEdit->SetReferences(this, mpInputRangeLabel);
45 0 : mpInputRangeButton->SetReferences(this, mpInputRangeEdit);
46 :
47 0 : get(mpOutputRangeLabel, "output-range-label");
48 0 : get(mpOutputRangeEdit, "output-range-edit");
49 0 : get(mpOutputRangeButton, "output-range-button");
50 0 : mpOutputRangeEdit->SetReferences(this, mpOutputRangeLabel);
51 0 : mpOutputRangeButton->SetReferences(this, mpOutputRangeEdit);
52 :
53 0 : get(mpSampleSize, "sample-size-spin");
54 0 : get(mpPeriod, "period-spin");
55 :
56 0 : get(mpRandomMethodRadio, "random-method-radio");
57 0 : get(mpPeriodicMethodRadio, "periodic-method-radio");
58 :
59 0 : get(mpButtonOk, "ok");
60 0 : get(mpButtonApply, "apply");
61 0 : get(mpButtonClose, "close");
62 :
63 0 : Init();
64 0 : GetRangeFromSelection();
65 0 : }
66 :
67 0 : void ScSamplingDialog::Init()
68 : {
69 0 : mpButtonOk->SetClickHdl( LINK( this, ScSamplingDialog, OkClicked ) );
70 0 : mpButtonClose->SetClickHdl( LINK( this, ScSamplingDialog, CloseClicked ) );
71 0 : mpButtonApply->SetClickHdl( LINK( this, ScSamplingDialog, ApplyClicked ) );
72 0 : mpButtonOk->Enable(false);
73 0 : mpButtonApply->Enable(false);
74 :
75 0 : Link aLink = LINK( this, ScSamplingDialog, GetFocusHandler );
76 0 : mpInputRangeEdit->SetGetFocusHdl( aLink );
77 0 : mpInputRangeButton->SetGetFocusHdl( aLink );
78 0 : mpOutputRangeEdit->SetGetFocusHdl( aLink );
79 0 : mpOutputRangeButton->SetGetFocusHdl( aLink );
80 :
81 0 : aLink = LINK( this, ScSamplingDialog, LoseFocusHandler );
82 0 : mpInputRangeEdit->SetLoseFocusHdl( aLink );
83 0 : mpInputRangeButton->SetLoseFocusHdl( aLink );
84 0 : mpOutputRangeEdit->SetLoseFocusHdl( aLink );
85 0 : mpOutputRangeButton->SetLoseFocusHdl( aLink );
86 :
87 0 : mpSampleSize->SetModifyHdl( LINK( this, ScSamplingDialog, SamplingSizeValueModified ));
88 :
89 0 : mpPeriodicMethodRadio->SetToggleHdl( LINK( this, ScSamplingDialog, ToggleSamplingMethod ) );
90 0 : mpRandomMethodRadio->SetToggleHdl( LINK( this, ScSamplingDialog, ToggleSamplingMethod ) );
91 :
92 0 : mpSampleSize->SetMin( 0 );
93 0 : mpSampleSize->SetMax( SAL_MAX_INT64 );
94 :
95 0 : mpOutputRangeEdit->GrabFocus();
96 0 : mpPeriodicMethodRadio->Check(true);
97 :
98 0 : ToggleSamplingMethod(NULL);
99 0 : }
100 :
101 0 : void ScSamplingDialog::GetRangeFromSelection()
102 : {
103 0 : mViewData->GetSimpleArea(mInputRange);
104 0 : OUString aCurrentString(mInputRange.Format(SCR_ABS_3D, mDocument, mAddressDetails));
105 0 : mpInputRangeEdit->SetText(aCurrentString);
106 0 : }
107 :
108 0 : ScSamplingDialog::~ScSamplingDialog()
109 0 : {}
110 :
111 0 : void ScSamplingDialog::SetActive()
112 : {
113 0 : if ( mDialogLostFocus )
114 : {
115 0 : mDialogLostFocus = false;
116 0 : if( mpActiveEdit )
117 0 : mpActiveEdit->GrabFocus();
118 : }
119 : else
120 : {
121 0 : GrabFocus();
122 : }
123 0 : RefInputDone();
124 0 : }
125 :
126 0 : bool ScSamplingDialog::Close()
127 : {
128 0 : return DoClose( ScSamplingDialogWrapper::GetChildWindowId() );
129 : }
130 :
131 0 : void ScSamplingDialog::SetReference( const ScRange& rReferenceRange, ScDocument* pDocument )
132 : {
133 0 : if ( mpActiveEdit )
134 : {
135 0 : if ( rReferenceRange.aStart != rReferenceRange.aEnd )
136 0 : RefInputStart( mpActiveEdit );
137 :
138 0 : OUString aReferenceString;
139 :
140 0 : if ( mpActiveEdit == mpInputRangeEdit )
141 : {
142 0 : mInputRange = rReferenceRange;
143 0 : aReferenceString = mInputRange.Format(SCR_ABS_3D, pDocument, mAddressDetails);
144 0 : mpInputRangeEdit->SetRefString( aReferenceString );
145 : }
146 0 : else if ( mpActiveEdit == mpOutputRangeEdit )
147 : {
148 0 : mOutputAddress = rReferenceRange.aStart;
149 :
150 0 : sal_uInt16 nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ? SCA_ABS : SCA_ABS_3D;
151 0 : aReferenceString = mOutputAddress.Format(nFormat, pDocument, pDocument->GetAddressConvention());
152 0 : mpOutputRangeEdit->SetRefString( aReferenceString );
153 :
154 : // Change sampling size according to output range selection
155 0 : sal_Int64 aSelectedSampleSize = rReferenceRange.aEnd.Row() - rReferenceRange.aStart.Row() + 1;
156 0 : if (aSelectedSampleSize > 1)
157 0 : mpSampleSize->SetValue(aSelectedSampleSize);
158 0 : SamplingSizeValueModified(NULL);
159 :
160 : // Enable OK, Cancel if output range is set
161 0 : mpButtonOk->Enable(!mpOutputRangeEdit->GetText().isEmpty());
162 0 : mpButtonApply->Enable(!mpOutputRangeEdit->GetText().isEmpty());
163 0 : }
164 : }
165 0 : }
166 :
167 0 : ScRange ScSamplingDialog::PerformPeriodicSampling(ScDocShell* pDocShell)
168 : {
169 0 : ScAddress aStart = mInputRange.aStart;
170 0 : ScAddress aEnd = mInputRange.aEnd;
171 :
172 0 : SCTAB outTab = mOutputAddress.Tab();
173 0 : SCCOL outCol = mOutputAddress.Col();
174 0 : SCROW outRow = mOutputAddress.Row();
175 :
176 0 : sal_Int64 aPeriod = mpPeriod->GetValue();
177 :
178 0 : for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
179 : {
180 0 : outCol = mOutputAddress.Col();
181 0 : for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
182 : {
183 0 : sal_Int64 i = 0;
184 0 : outRow = mOutputAddress.Row();
185 0 : for (SCROW inRow = aStart.Row(); inRow <= aEnd.Row(); inRow++)
186 : {
187 0 : if (i % aPeriod == aPeriod - 1 ) // Sample the last of period
188 : {
189 0 : double aValue = mDocument->GetValue(ScAddress(inCol, inRow, inTab));
190 0 : pDocShell->GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), aValue, true);
191 0 : outRow++;
192 : }
193 0 : i++;
194 : }
195 0 : outCol++;
196 : }
197 0 : outTab++;
198 : }
199 :
200 0 : return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
201 : }
202 :
203 0 : ScRange ScSamplingDialog::PerformRandomSampling(ScDocShell* pDocShell)
204 : {
205 0 : ScAddress aStart = mInputRange.aStart;
206 0 : ScAddress aEnd = mInputRange.aEnd;
207 :
208 0 : SCTAB outTab = mOutputAddress.Tab();
209 0 : SCCOL outCol = mOutputAddress.Col();
210 0 : SCROW outRow = mOutputAddress.Row();
211 :
212 : TimeValue now;
213 0 : osl_getSystemTime(&now);
214 0 : boost::mt19937 seed(now.Nanosec);
215 0 : boost::uniform_01<boost::mt19937> rng(seed);
216 :
217 : SCROW inRow;
218 :
219 0 : sal_Int64 aSampleSize = mpSampleSize->GetValue();
220 :
221 0 : for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
222 : {
223 0 : outCol = mOutputAddress.Col();
224 0 : for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
225 : {
226 0 : SCROW aPopulationSize = (aEnd.Row() - aStart.Row()) + 1;
227 :
228 0 : outRow = mOutputAddress.Row();
229 0 : inRow = aStart.Row();
230 :
231 : double aRandomValue;
232 :
233 0 : while ((outRow - mOutputAddress.Row()) < aSampleSize)
234 : {
235 0 : aRandomValue = rng();
236 :
237 0 : if ( (aPopulationSize - (inRow - aStart.Row())) * aRandomValue >= aSampleSize - (outRow - mOutputAddress.Row()) )
238 : {
239 0 : inRow++;
240 : }
241 : else
242 : {
243 0 : double aValue = mDocument->GetValue( ScAddress(inCol, inRow, inTab) );
244 0 : pDocShell->GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), aValue, true);
245 0 : inRow++;
246 0 : outRow++;
247 : }
248 : }
249 0 : outCol++;
250 : }
251 0 : outTab++;
252 : }
253 :
254 0 : return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
255 : }
256 :
257 0 : void ScSamplingDialog::PerformSampling()
258 : {
259 0 : OUString aUndo( SC_STRLOAD( RID_STATISTICS_DLGS, STR_SAMPLING_UNDO_NAME));
260 0 : ScDocShell* pDocShell = mViewData->GetDocShell();
261 0 : svl::IUndoManager* pUndoManager = pDocShell->GetUndoManager();
262 :
263 0 : ScRange aModifiedRange;
264 :
265 0 : pUndoManager->EnterListAction( aUndo, aUndo );
266 :
267 0 : if (mpRandomMethodRadio->IsChecked())
268 : {
269 0 : aModifiedRange = PerformRandomSampling(pDocShell);
270 : }
271 0 : else if (mpPeriodicMethodRadio->IsChecked())
272 : {
273 0 : aModifiedRange = PerformPeriodicSampling(pDocShell);
274 : }
275 :
276 0 : pUndoManager->LeaveListAction();
277 0 : pDocShell->PostPaint(aModifiedRange, PAINT_GRID);
278 0 : }
279 :
280 0 : IMPL_LINK( ScSamplingDialog, OkClicked, PushButton*, /*pButton*/ )
281 : {
282 0 : ApplyClicked(NULL);
283 0 : CloseClicked(NULL);
284 0 : return 0;
285 : }
286 :
287 :
288 0 : IMPL_LINK( ScSamplingDialog, ApplyClicked, PushButton*, /*pButton*/ )
289 : {
290 0 : PerformSampling();
291 0 : return 0;
292 : }
293 :
294 0 : IMPL_LINK( ScSamplingDialog, CloseClicked, PushButton*, /*pButton*/ )
295 : {
296 0 : Close();
297 0 : return 0;
298 : }
299 :
300 0 : IMPL_LINK( ScSamplingDialog, GetFocusHandler, Control*, pCtrl )
301 : {
302 0 : mpActiveEdit = NULL;
303 :
304 0 : if( (pCtrl == (Control*) mpInputRangeEdit) || (pCtrl == (Control*) mpInputRangeButton) )
305 0 : mpActiveEdit = mpInputRangeEdit;
306 0 : else if( (pCtrl == (Control*) mpOutputRangeEdit) || (pCtrl == (Control*) mpOutputRangeButton) )
307 0 : mpActiveEdit = mpOutputRangeEdit;
308 :
309 0 : if( mpActiveEdit )
310 0 : mpActiveEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
311 :
312 0 : return 0;
313 : }
314 :
315 0 : IMPL_LINK_NOARG(ScSamplingDialog, LoseFocusHandler)
316 : {
317 0 : mDialogLostFocus = !IsActive();
318 0 : return 0;
319 : }
320 :
321 0 : IMPL_LINK_NOARG(ScSamplingDialog, SamplingSizeValueModified)
322 : {
323 0 : sal_Int64 aPopulationSize = mInputRange.aEnd.Row() - mInputRange.aStart.Row() + 1;
324 0 : if (mpSampleSize->GetValue() > aPopulationSize)
325 0 : mpSampleSize->SetValue(aPopulationSize);
326 0 : return 0;
327 : }
328 :
329 0 : IMPL_LINK_NOARG(ScSamplingDialog, ToggleSamplingMethod)
330 : {
331 0 : if (mpRandomMethodRadio->IsChecked())
332 : {
333 0 : mpPeriod->Enable(false);
334 0 : mpSampleSize->Enable(true);
335 : }
336 0 : else if (mpPeriodicMethodRadio->IsChecked())
337 : {
338 0 : mpPeriod->Enable(true);
339 0 : mpSampleSize->Enable(false);
340 : }
341 0 : return 0;
342 0 : }
343 :
344 :
345 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|