Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/StatisticsDialogs/SamplingDialog.cxx
Line
Count
Source
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 <svl/undo.hxx>
12
#include <comphelper/random.hxx>
13
#include <rangelst.hxx>
14
#include <docsh.hxx>
15
#include <document.hxx>
16
#include <reffact.hxx>
17
#include <docfunc.hxx>
18
#include <SamplingDialog.hxx>
19
#include <scresid.hxx>
20
#include <strings.hrc>
21
22
ScSamplingDialog::ScSamplingDialog(SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
23
                                   weld::Window* pParent, ScViewData& rViewData)
24
0
    : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent,
25
0
                          u"modules/scalc/ui/samplingdialog.ui"_ustr, u"SamplingDialog"_ustr)
26
0
    , mpActiveEdit(nullptr)
27
0
    , mViewData(rViewData)
28
0
    , mDocument(rViewData.GetDocument())
29
0
    , mInputRange(ScAddress::INITIALIZE_INVALID)
30
0
    , mAddressDetails(mDocument.GetAddressConvention(), 0, 0)
31
0
    , mOutputAddress(ScAddress::INITIALIZE_INVALID)
32
0
    , mCurrentAddress(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.CurrentTabForData())
33
0
    , mnLastSampleSizeValue(1)
34
0
    , mnLastPeriodValue(1)
35
0
    , mDialogLostFocus(false)
36
0
    , mxInputRangeLabel(m_xBuilder->weld_label(u"input-range-label"_ustr))
37
0
    , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry(u"input-range-edit"_ustr)))
38
0
    , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button(u"input-range-button"_ustr)))
39
0
    , mxOutputRangeLabel(m_xBuilder->weld_label(u"output-range-label"_ustr))
40
0
    , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry(u"output-range-edit"_ustr)))
41
0
    , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button(u"output-range-button"_ustr)))
42
0
    , mxSampleSize(m_xBuilder->weld_spin_button(u"sample-size-spin"_ustr))
43
0
    , mxPeriod(m_xBuilder->weld_spin_button(u"period-spin"_ustr))
44
0
    , mxRandomMethodRadio(m_xBuilder->weld_radio_button(u"random-method-radio"_ustr))
45
0
    , mxWithReplacement(m_xBuilder->weld_check_button(u"with-replacement"_ustr))
46
0
    , mxKeepOrder(m_xBuilder->weld_check_button(u"keep-order"_ustr))
47
0
    , mxPeriodicMethodRadio(m_xBuilder->weld_radio_button(u"periodic-method-radio"_ustr))
48
0
    , mxButtonOk(m_xBuilder->weld_button(u"ok"_ustr))
49
0
    , mxButtonCancel(m_xBuilder->weld_button(u"cancel"_ustr))
50
0
{
51
0
    mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get());
52
0
    mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get());
53
54
0
    mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get());
55
0
    mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get());
56
57
0
    Init();
58
0
    GetRangeFromSelection();
59
0
}
60
61
ScSamplingDialog::~ScSamplingDialog()
62
0
{
63
0
}
64
65
void ScSamplingDialog::Init()
66
0
{
67
0
    mxButtonCancel->connect_clicked( LINK( this, ScSamplingDialog, ButtonClicked ) );
68
0
    mxButtonOk->connect_clicked( LINK( this, ScSamplingDialog, ButtonClicked ) );
69
0
    mxButtonOk->set_sensitive(false);
70
71
0
    Link<formula::RefEdit&,void> aEditLink = LINK( this, ScSamplingDialog, GetEditFocusHandler );
72
0
    mxInputRangeEdit->SetGetFocusHdl( aEditLink );
73
0
    mxOutputRangeEdit->SetGetFocusHdl( aEditLink );
74
0
    Link<formula::RefButton&,void> aButtonLink = LINK( this, ScSamplingDialog, GetButtonFocusHandler );
75
0
    mxInputRangeButton->SetGetFocusHdl( aButtonLink );
76
0
    mxOutputRangeButton->SetGetFocusHdl( aButtonLink );
77
78
0
    aEditLink = LINK( this, ScSamplingDialog, LoseEditFocusHandler );
79
0
    mxInputRangeEdit->SetLoseFocusHdl( aEditLink );
80
0
    mxOutputRangeEdit->SetLoseFocusHdl( aEditLink );
81
0
    aButtonLink = LINK( this, ScSamplingDialog, LoseButtonFocusHandler );
82
0
    mxInputRangeButton->SetLoseFocusHdl( aButtonLink );
83
0
    mxOutputRangeButton->SetLoseFocusHdl( aButtonLink );
84
85
0
    Link<formula::RefEdit&,void> aLink2 = LINK( this, ScSamplingDialog, RefInputModifyHandler);
86
0
    mxInputRangeEdit->SetModifyHdl( aLink2);
87
0
    mxOutputRangeEdit->SetModifyHdl( aLink2);
88
89
0
    mxSampleSize->connect_value_changed( LINK( this, ScSamplingDialog, SamplingSizeValueModified ));
90
0
    mxSampleSize->set_range(1, SAL_MAX_INT32);
91
0
    mxPeriod->connect_value_changed( LINK( this, ScSamplingDialog, PeriodValueModified ));
92
0
    mxPeriod->set_range(1, SAL_MAX_INT32);
93
94
0
    mxPeriodicMethodRadio->connect_toggled( LINK( this, ScSamplingDialog, ToggleSamplingMethod ) );
95
0
    mxRandomMethodRadio->connect_toggled( LINK( this, ScSamplingDialog, ToggleSamplingMethod ) );
96
97
0
    mxWithReplacement->connect_toggled( LINK( this, ScSamplingDialog, CheckHdl));
98
0
    mxKeepOrder->connect_toggled( LINK( this, ScSamplingDialog, CheckHdl));
99
100
0
    mxOutputRangeEdit->GrabFocus();
101
0
    mxPeriodicMethodRadio->set_active(true);
102
103
0
    ToggleSamplingMethod();
104
0
}
105
106
void ScSamplingDialog::GetRangeFromSelection()
107
0
{
108
0
    mViewData.GetSimpleArea(mInputRange);
109
0
    OUString aCurrentString(mInputRange.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails));
110
0
    mxInputRangeEdit->SetText(aCurrentString);
111
0
}
112
113
void ScSamplingDialog::SetActive()
114
0
{
115
0
    if ( mDialogLostFocus )
116
0
    {
117
0
        mDialogLostFocus = false;
118
0
        if( mpActiveEdit )
119
0
            mpActiveEdit->GrabFocus();
120
0
    }
121
0
    else
122
0
    {
123
0
        m_xDialog->grab_focus();
124
0
    }
125
0
    RefInputDone();
126
0
}
127
128
void ScSamplingDialog::Close()
129
0
{
130
0
    DoClose( ScSamplingDialogWrapper::GetChildWindowId() );
131
0
}
132
133
void ScSamplingDialog::SetReference( const ScRange& rReferenceRange, ScDocument& rDocument )
134
0
{
135
0
    if ( mpActiveEdit )
136
0
    {
137
0
        if ( rReferenceRange.aStart != rReferenceRange.aEnd )
138
0
            RefInputStart( mpActiveEdit );
139
140
0
        OUString aReferenceString;
141
142
0
        if ( mpActiveEdit == mxInputRangeEdit.get() )
143
0
        {
144
0
            mInputRange = rReferenceRange;
145
0
            aReferenceString = mInputRange.Format(rDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
146
0
            mxInputRangeEdit->SetRefString( aReferenceString );
147
148
0
            LimitSampleSizeAndPeriod();
149
0
        }
150
0
        else if ( mpActiveEdit == mxOutputRangeEdit.get() )
151
0
        {
152
0
            mOutputAddress = rReferenceRange.aStart;
153
154
0
            ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
155
0
                                                             ScRefFlags::ADDR_ABS :
156
0
                                                             ScRefFlags::ADDR_ABS_3D;
157
0
            aReferenceString = mOutputAddress.Format(nFormat, &rDocument, rDocument.GetAddressConvention());
158
0
            mxOutputRangeEdit->SetRefString( aReferenceString );
159
160
            // Change sampling size according to output range selection
161
0
            sal_Int64 aSelectedSampleSize = rReferenceRange.aEnd.Row() - rReferenceRange.aStart.Row() + 1;
162
0
            if (aSelectedSampleSize > 1)
163
0
                mxSampleSize->set_value(aSelectedSampleSize);
164
0
            SamplingSizeValueModified(*mxSampleSize);
165
0
        }
166
0
    }
167
168
    // Enable OK if both, input range and output address are set.
169
    // Disable if at least one is invalid.
170
0
    mxButtonOk->set_sensitive(mInputRange.IsValid() && mOutputAddress.IsValid());
171
0
}
172
173
ScRange ScSamplingDialog::PerformPeriodicSampling(ScDocShell& rDocShell)
174
0
{
175
0
    ScAddress aStart = mInputRange.aStart;
176
0
    ScAddress aEnd   = mInputRange.aEnd;
177
178
0
    SCTAB outTab = mOutputAddress.Tab();
179
0
    SCROW outRow = mOutputAddress.Row();
180
181
0
    sal_Int64 aPeriod = mxPeriod->get_value();
182
183
0
    for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
184
0
    {
185
0
        SCCOL outCol = mOutputAddress.Col();
186
0
        for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
187
0
        {
188
0
            sal_Int64 i = 0;
189
0
            outRow = mOutputAddress.Row();
190
0
            for (SCROW inRow = aStart.Row(); inRow <= aEnd.Row(); inRow++)
191
0
            {
192
0
                assert(aPeriod && "div-by-zero");
193
0
                if (i % aPeriod == aPeriod - 1 ) // Sample the last of period
194
0
                {
195
0
                    double aValue = mDocument.GetValue(ScAddress(inCol, inRow, inTab));
196
0
                    rDocShell.GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), aValue, true);
197
0
                    outRow++;
198
0
                }
199
0
                i++;
200
0
            }
201
0
            outCol++;
202
0
        }
203
0
        outTab++;
204
0
    }
205
206
0
    return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
207
0
}
208
209
ScRange ScSamplingDialog::PerformRandomSampling(ScDocShell& rDocShell)
210
0
{
211
0
    ScAddress aStart = mInputRange.aStart;
212
0
    ScAddress aEnd   = mInputRange.aEnd;
213
214
0
    SCTAB outTab = mOutputAddress.Tab();
215
0
    SCROW outRow = mOutputAddress.Row();
216
217
0
    const sal_Int64 nSampleSize = mxSampleSize->get_value();
218
219
    // This implementation groups by columns. Other options could be grouping
220
    // by rows or area.
221
0
    const sal_Int64 nPopulationSize = aEnd.Row() - aStart.Row() + 1;
222
223
0
    const bool bWithReplacement = mxWithReplacement->get_sensitive() && mxWithReplacement->get_active();
224
225
    // WOR (WithOutReplacement) can't draw more than population. Catch that in
226
    // the caller.
227
0
    assert( bWithReplacement || nSampleSize <= nPopulationSize);
228
0
    if (!bWithReplacement && nSampleSize > nPopulationSize)
229
        // Would enter an endless loop below, bail out.
230
0
        return ScRange( mOutputAddress);
231
232
0
    for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
233
0
    {
234
0
        SCCOL outCol = mOutputAddress.Col();
235
0
        for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
236
0
        {
237
0
            outRow = mOutputAddress.Row();
238
0
            std::vector<bool> vUsed( nPopulationSize, false);
239
240
0
            while ((outRow - mOutputAddress.Row()) < nSampleSize)
241
0
            {
242
                // [a,b] *both* inclusive
243
0
                SCROW nRandom = comphelper::rng::uniform_int_distribution( aStart.Row(), aEnd.Row());
244
245
0
                if (!bWithReplacement)
246
0
                {
247
0
                    nRandom -= aStart.Row();
248
0
                    if (vUsed[nRandom])
249
0
                    {
250
                        // Find a nearest one, preferring forwards.
251
                        // Again: it's essential that the loop is entered only
252
                        // if nSampleSize<=nPopulationSize, which is checked
253
                        // above.
254
0
                        SCROW nBack = nRandom;
255
0
                        SCROW nForw = nRandom;
256
0
                        do
257
0
                        {
258
0
                            if (nForw < nPopulationSize - 1 && !vUsed[++nForw])
259
0
                            {
260
0
                                nRandom = nForw;
261
0
                                break;
262
0
                            }
263
0
                            if (nBack > 0 && !vUsed[--nBack])
264
0
                            {
265
0
                                nRandom = nBack;
266
0
                                break;
267
0
                            }
268
0
                        }
269
0
                        while (true);
270
0
                    }
271
0
                    vUsed[nRandom] = true;
272
0
                    nRandom += aStart.Row();
273
0
                }
274
275
0
                const double fValue = mDocument.GetValue( ScAddress(inCol, nRandom, inTab) );
276
0
                rDocShell.GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), fValue, true);
277
0
                outRow++;
278
0
            }
279
0
            outCol++;
280
0
        }
281
0
        outTab++;
282
0
    }
283
284
0
    return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
285
0
}
286
287
ScRange ScSamplingDialog::PerformRandomSamplingKeepOrder(ScDocShell& rDocShell)
288
0
{
289
0
    ScAddress aStart = mInputRange.aStart;
290
0
    ScAddress aEnd   = mInputRange.aEnd;
291
292
0
    SCTAB outTab = mOutputAddress.Tab();
293
0
    SCROW outRow = mOutputAddress.Row();
294
295
0
    SCROW inRow;
296
297
0
    sal_Int64 aSampleSize = mxSampleSize->get_value();
298
299
0
    for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
300
0
    {
301
0
        SCCOL outCol = mOutputAddress.Col();
302
0
        for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
303
0
        {
304
0
            SCROW aPopulationSize = (aEnd.Row() - aStart.Row()) + 1;
305
306
0
            outRow = mOutputAddress.Row();
307
0
            inRow  = aStart.Row();
308
309
0
            while ((outRow - mOutputAddress.Row()) < aSampleSize)
310
0
            {
311
0
                double aRandomValue = comphelper::rng::uniform_real_distribution();
312
313
0
                if ( (aPopulationSize - (inRow - aStart.Row())) * aRandomValue >= aSampleSize - (outRow - mOutputAddress.Row()) )
314
0
                {
315
0
                    inRow++;
316
0
                }
317
0
                else
318
0
                {
319
0
                    double aValue = mDocument.GetValue( ScAddress(inCol, inRow, inTab) );
320
0
                    rDocShell.GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), aValue, true);
321
0
                    inRow++;
322
0
                    outRow++;
323
0
                }
324
0
            }
325
0
            outCol++;
326
0
        }
327
0
        outTab++;
328
0
    }
329
330
0
    return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
331
0
}
332
333
void ScSamplingDialog::PerformSampling()
334
0
{
335
0
    OUString aUndo(ScResId(STR_SAMPLING_UNDO_NAME));
336
0
    ScDocShell& rDocShell = mViewData.GetDocShell();
337
0
    SfxUndoManager* pUndoManager = rDocShell.GetUndoManager();
338
339
0
    ScRange aModifiedRange;
340
341
0
    pUndoManager->EnterListAction( aUndo, aUndo, 0, mViewData.GetViewShell()->GetViewShellId() );
342
343
0
    if (mxRandomMethodRadio->get_active())
344
0
    {
345
0
        if (mxKeepOrder->get_sensitive() && mxKeepOrder->get_active())
346
0
            aModifiedRange = PerformRandomSamplingKeepOrder(rDocShell);
347
0
        else
348
0
            aModifiedRange = PerformRandomSampling(rDocShell);
349
0
    }
350
0
    else if (mxPeriodicMethodRadio->get_active())
351
0
    {
352
0
        aModifiedRange = PerformPeriodicSampling(rDocShell);
353
0
    }
354
355
0
    pUndoManager->LeaveListAction();
356
0
    rDocShell.PostPaint(aModifiedRange, PaintPartFlags::Grid);
357
0
}
358
359
sal_Int64 ScSamplingDialog::GetPopulationSize() const
360
0
{
361
0
    return mInputRange.IsValid() ? mInputRange.aEnd.Row() - mInputRange.aStart.Row() + 1 : 0;
362
0
}
363
364
void ScSamplingDialog::LimitSampleSizeAndPeriod()
365
0
{
366
    // Limit sample size (for WOR methods) and period if population is smaller
367
    // than last known value. When enlarging the input population range the
368
    // values will be adjusted up to the last known value again.
369
0
    const sal_Int64 nPopulationSize = GetPopulationSize();
370
0
    if (nPopulationSize <= mnLastSampleSizeValue && !mxWithReplacement->get_active())
371
0
        mxSampleSize->set_value( nPopulationSize);
372
0
    if (nPopulationSize <= mnLastPeriodValue)
373
0
        mxPeriod->set_value( nPopulationSize);
374
0
}
375
376
IMPL_LINK_NOARG(ScSamplingDialog, SamplingSizeValueModified, weld::SpinButton&, void)
377
0
{
378
0
    if (!mxWithReplacement->get_active())
379
0
    {
380
        // For all WOR methods limit sample size to population size.
381
0
        const sal_Int64 nPopulationSize = GetPopulationSize();
382
0
        if (mxSampleSize->get_value() > nPopulationSize)
383
0
            mxSampleSize->set_value(nPopulationSize);
384
0
    }
385
0
    mnLastSampleSizeValue = mxSampleSize->get_value();
386
0
}
387
388
IMPL_LINK_NOARG(ScSamplingDialog, PeriodValueModified, weld::SpinButton&, void)
389
0
{
390
    // Limit period to population size.
391
0
    const sal_Int64 nPopulationSize = GetPopulationSize();
392
0
    if (mxPeriod->get_value() > nPopulationSize)
393
0
        mxPeriod->set_value(nPopulationSize);
394
0
    mnLastPeriodValue = mxPeriod->get_value();
395
0
}
396
397
IMPL_LINK( ScSamplingDialog, GetEditFocusHandler, formula::RefEdit&, rCtrl, void )
398
0
{
399
0
    if (&rCtrl == mxInputRangeEdit.get())
400
0
        mpActiveEdit = mxInputRangeEdit.get();
401
0
    else if (&rCtrl == mxOutputRangeEdit.get())
402
0
        mpActiveEdit = mxOutputRangeEdit.get();
403
0
    else
404
0
        mpActiveEdit = nullptr;
405
406
0
    if (mpActiveEdit)
407
0
        mpActiveEdit->SelectAll();
408
0
}
409
410
IMPL_LINK(ScSamplingDialog, GetButtonFocusHandler, formula::RefButton&, rCtrl, void)
411
0
{
412
0
    if (&rCtrl == mxInputRangeButton.get())
413
0
        mpActiveEdit = mxInputRangeEdit.get();
414
0
    else if (&rCtrl == mxOutputRangeButton.get())
415
0
        mpActiveEdit = mxOutputRangeEdit.get();
416
0
    else
417
0
        mpActiveEdit = nullptr;
418
419
0
    if (mpActiveEdit)
420
0
        mpActiveEdit->SelectAll();
421
0
}
422
423
424
IMPL_LINK(ScSamplingDialog, ButtonClicked, weld::Button&, rButton, void)
425
0
{
426
0
    if (&rButton == mxButtonOk.get())
427
0
    {
428
0
        PerformSampling();
429
0
        response(RET_OK);
430
0
    }
431
0
    else
432
0
        response(RET_CANCEL);
433
0
}
434
435
IMPL_LINK_NOARG(ScSamplingDialog, LoseEditFocusHandler, formula::RefEdit&, void)
436
0
{
437
0
    mDialogLostFocus = !m_xDialog->has_toplevel_focus();
438
0
}
439
440
IMPL_LINK_NOARG(ScSamplingDialog, LoseButtonFocusHandler, formula::RefButton&, void)
441
0
{
442
0
    mDialogLostFocus = !m_xDialog->has_toplevel_focus();
443
0
}
444
445
IMPL_LINK_NOARG(ScSamplingDialog, ToggleSamplingMethod, weld::Toggleable&, void)
446
0
{
447
0
    ToggleSamplingMethod();
448
0
}
449
450
void ScSamplingDialog::ToggleSamplingMethod()
451
0
{
452
0
    if (mxRandomMethodRadio->get_active())
453
0
    {
454
0
        mxPeriod->set_sensitive(false);
455
0
        mxSampleSize->set_sensitive(true);
456
0
        mxWithReplacement->set_sensitive(true);
457
0
        mxKeepOrder->set_sensitive(true);
458
0
    }
459
0
    else if (mxPeriodicMethodRadio->get_active())
460
0
    {
461
        // WOR keeping order.
462
0
        mxPeriod->set_sensitive(true);
463
0
        mxSampleSize->set_sensitive(false);
464
0
        mxWithReplacement->set_active(false);
465
0
        mxWithReplacement->set_sensitive(false);
466
0
        mxKeepOrder->set_active(true);
467
0
        mxKeepOrder->set_sensitive(false);
468
0
    }
469
0
}
470
471
IMPL_LINK(ScSamplingDialog, CheckHdl, weld::Toggleable&, rBtn, void)
472
0
{
473
    // Keep both checkboxes enabled so user can easily switch between the three
474
    // possible combinations (one or the other or none), just uncheck the other
475
    // one if one is checked. Otherwise the other checkbox would had to be
476
    // disabled until user unchecks the enabled one again, which would force
477
    // user to two clicks to switch.
478
0
    if (&rBtn == mxWithReplacement.get())
479
0
    {
480
0
        if (mxWithReplacement->get_active())
481
0
        {
482
            // For WR can't keep order.
483
0
            mxKeepOrder->set_active(false);
484
0
        }
485
0
        else
486
0
        {
487
            // For WOR limit sample size to population size.
488
0
            SamplingSizeValueModified(*mxSampleSize);
489
0
        }
490
0
    }
491
0
    else if (&rBtn == mxKeepOrder.get())
492
0
    {
493
0
        if (mxKeepOrder->get_active())
494
0
        {
495
            // Keep order is always WOR.
496
0
            mxWithReplacement->set_active(false);
497
0
            SamplingSizeValueModified(*mxSampleSize);
498
0
        }
499
0
    }
500
0
}
501
502
IMPL_LINK_NOARG(ScSamplingDialog, RefInputModifyHandler, formula::RefEdit&, void)
503
0
{
504
0
    if ( mpActiveEdit )
505
0
    {
506
0
        if ( mpActiveEdit == mxInputRangeEdit.get() )
507
0
        {
508
0
            ScRangeList aRangeList;
509
0
            bool bValid = ParseWithNames( aRangeList, mxInputRangeEdit->GetText(), mDocument);
510
0
            const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
511
0
            if (pRange)
512
0
            {
513
0
                mInputRange = *pRange;
514
                // Highlight the resulting range.
515
0
                mxInputRangeEdit->StartUpdateData();
516
517
0
                LimitSampleSizeAndPeriod();
518
0
            }
519
0
            else
520
0
            {
521
0
                mInputRange = ScRange( ScAddress::INITIALIZE_INVALID);
522
0
            }
523
0
        }
524
0
        else if ( mpActiveEdit == mxOutputRangeEdit.get() )
525
0
        {
526
0
            ScRangeList aRangeList;
527
0
            bool bValid = ParseWithNames( aRangeList, mxOutputRangeEdit->GetText(), mDocument);
528
0
            const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
529
0
            if (pRange)
530
0
            {
531
0
                mOutputAddress = pRange->aStart;
532
533
                // Crop output range to top left address for Edit field.
534
0
                if (pRange->aStart != pRange->aEnd)
535
0
                {
536
0
                    ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
537
0
                                                                     ScRefFlags::ADDR_ABS :
538
0
                                                                     ScRefFlags::ADDR_ABS_3D;
539
0
                    OUString aReferenceString = mOutputAddress.Format(nFormat, &mDocument, mDocument.GetAddressConvention());
540
0
                    mxOutputRangeEdit->SetRefString( aReferenceString );
541
0
                }
542
543
                // Change sampling size according to output range selection
544
0
                sal_Int64 aSelectedSampleSize = pRange->aEnd.Row() - pRange->aStart.Row() + 1;
545
0
                if (aSelectedSampleSize > 1)
546
0
                    mxSampleSize->set_value(aSelectedSampleSize);
547
0
                SamplingSizeValueModified(*mxSampleSize);
548
549
                // Highlight the resulting range.
550
0
                mxOutputRangeEdit->StartUpdateData();
551
0
            }
552
0
            else
553
0
            {
554
0
                mOutputAddress = ScAddress( ScAddress::INITIALIZE_INVALID);
555
0
            }
556
0
        }
557
0
    }
558
559
    // Enable OK if both, input range and output address are set.
560
0
    mxButtonOk->set_sensitive(mInputRange.IsValid() && mOutputAddress.IsValid());
561
0
}
562
563
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */