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