Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/StatisticsDialogs/StatisticsInputOutputDialog.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 <vcl/weld/Dialog.hxx>
13
14
#include <rangelst.hxx>
15
#include <docsh.hxx>
16
#include <document.hxx>
17
#include <scresid.hxx>
18
#include <tabvwsh.hxx>
19
20
#include <StatisticsInputOutputDialog.hxx>
21
22
ScRangeList ScStatisticsInputOutputDialog::MakeColumnRangeList(SCTAB aTab, ScAddress const & aStart, ScAddress const & aEnd)
23
0
{
24
0
    ScRangeList aRangeList;
25
0
    for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
26
0
    {
27
0
        ScRange aColumnRange (
28
0
            ScAddress(inCol, aStart.Row(), aTab),
29
0
            ScAddress(inCol, aEnd.Row(),   aTab) );
30
31
0
        aRangeList.push_back(aColumnRange);
32
0
    }
33
0
    return aRangeList;
34
0
}
35
36
ScRangeList ScStatisticsInputOutputDialog::MakeRowRangeList(SCTAB aTab, ScAddress const & aStart, ScAddress const & aEnd)
37
0
{
38
0
    ScRangeList aRangeList;
39
0
    for (SCROW inRow = aStart.Row(); inRow <= aEnd.Row(); inRow++)
40
0
    {
41
0
        ScRange aRowRange (
42
0
            ScAddress(aStart.Col(), inRow, aTab),
43
0
            ScAddress(aEnd.Col(),   inRow, aTab) );
44
45
0
        aRangeList.push_back(aRowRange);
46
0
    }
47
0
    return aRangeList;
48
0
}
49
50
ScStatisticsInputOutputDialog::ScStatisticsInputOutputDialog(
51
                    SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
52
                    weld::Window* pParent, ScViewData& rViewData, const OUString& rUIXMLDescription, const OUString& rID)
53
0
    : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent, rUIXMLDescription, rID)
54
0
    , mxInputRangeLabel(m_xBuilder->weld_label(u"input-range-label"_ustr))
55
0
    , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry(u"input-range-edit"_ustr)))
56
0
    , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button(u"input-range-button"_ustr)))
57
0
    , mxOutputRangeLabel(m_xBuilder->weld_label(u"output-range-label"_ustr))
58
0
    , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry(u"output-range-edit"_ustr)))
59
0
    , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button(u"output-range-button"_ustr)))
60
0
    , mxGroupByColumnsRadio(m_xBuilder->weld_radio_button(u"groupedby-columns-radio"_ustr))
61
0
    , mxGroupByRowsRadio(m_xBuilder->weld_radio_button(u"groupedby-rows-radio"_ustr))
62
0
    , mViewData(rViewData)
63
0
    , mDocument(rViewData.GetDocument())
64
0
    , mInputRange(ScAddress::INITIALIZE_INVALID)
65
0
    , mAddressDetails(mDocument.GetAddressConvention(), 0, 0)
66
0
    , mOutputAddress(ScAddress::INITIALIZE_INVALID)
67
0
    , mGroupedBy(GroupedBy::ByColumn)
68
0
    , mxButtonOk(m_xBuilder->weld_button(u"ok"_ustr))
69
0
    , mxButtonCancel(m_xBuilder->weld_button(u"cancel"_ustr))
70
0
    , mpActiveEdit(nullptr)
71
0
    , mCurrentAddress(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.CurrentTabForData())
72
0
    , mDialogLostFocus(false)
73
0
{
74
0
    mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get());
75
0
    mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get());
76
77
0
    mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get());
78
0
    mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get());
79
80
0
    Init();
81
0
    GetRangeFromSelection();
82
0
}
83
84
ScStatisticsInputOutputDialog::~ScStatisticsInputOutputDialog()
85
0
{
86
0
}
87
88
void ScStatisticsInputOutputDialog::Init()
89
0
{
90
0
    mxButtonCancel->connect_clicked( LINK( this, ScStatisticsInputOutputDialog, ButtonClicked ) );
91
0
    mxButtonOk->connect_clicked( LINK( this, ScStatisticsInputOutputDialog, ButtonClicked ) );
92
0
    mxButtonOk->set_sensitive(false);
93
94
0
    Link<formula::RefEdit&,void> aEditLink = LINK( this, ScStatisticsInputOutputDialog, GetEditFocusHandler );
95
0
    mxInputRangeEdit->SetGetFocusHdl( aEditLink );
96
0
    mxOutputRangeEdit->SetGetFocusHdl( aEditLink );
97
0
    Link<formula::RefButton&,void> aButtonLink = LINK( this, ScStatisticsInputOutputDialog, GetButtonFocusHandler );
98
0
    mxInputRangeButton->SetGetFocusHdl( aButtonLink );
99
0
    mxOutputRangeButton->SetGetFocusHdl( aButtonLink );
100
101
0
    aEditLink = LINK( this, ScStatisticsInputOutputDialog, LoseEditFocusHandler );
102
0
    mxInputRangeEdit->SetLoseFocusHdl( aEditLink );
103
0
    mxOutputRangeEdit->SetLoseFocusHdl( aEditLink );
104
0
    aButtonLink = LINK( this, ScStatisticsInputOutputDialog, LoseButtonFocusHandler );
105
0
    mxInputRangeButton->SetLoseFocusHdl( aButtonLink );
106
0
    mxOutputRangeButton->SetLoseFocusHdl( aButtonLink );
107
108
0
    Link<formula::RefEdit&,void> aLink2 = LINK( this, ScStatisticsInputOutputDialog, RefInputModifyHandler);
109
0
    mxInputRangeEdit->SetModifyHdl( aLink2);
110
0
    mxOutputRangeEdit->SetModifyHdl( aLink2);
111
112
0
    mxOutputRangeEdit->GrabFocus();
113
114
0
    mxGroupByColumnsRadio->connect_toggled( LINK( this, ScStatisticsInputOutputDialog, GroupByChanged ) );
115
0
    mxGroupByRowsRadio->connect_toggled( LINK( this, ScStatisticsInputOutputDialog, GroupByChanged ) );
116
117
0
    mxGroupByColumnsRadio->set_active(true);
118
0
    mxGroupByRowsRadio->set_active(false);
119
0
}
120
121
void ScStatisticsInputOutputDialog::GetRangeFromSelection()
122
0
{
123
0
    mViewData.GetSimpleArea(mInputRange);
124
0
    OUString aCurrentString(mInputRange.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails));
125
0
    mxInputRangeEdit->SetText(aCurrentString);
126
0
}
127
128
void ScStatisticsInputOutputDialog::SetActive()
129
0
{
130
0
    if ( mDialogLostFocus )
131
0
    {
132
0
        mDialogLostFocus = false;
133
0
        if( mpActiveEdit )
134
0
            mpActiveEdit->GrabFocus();
135
0
    }
136
0
    else
137
0
    {
138
0
        m_xDialog->grab_focus();
139
0
    }
140
0
    RefInputDone();
141
0
}
142
143
void ScStatisticsInputOutputDialog::SetReference( const ScRange& rReferenceRange, ScDocument& rDocument )
144
0
{
145
0
    if ( mpActiveEdit )
146
0
    {
147
0
        if ( rReferenceRange.aStart != rReferenceRange.aEnd )
148
0
            RefInputStart( mpActiveEdit );
149
150
0
        OUString aReferenceString;
151
152
0
        if (mpActiveEdit == mxInputRangeEdit.get())
153
0
        {
154
0
            mInputRange = rReferenceRange;
155
0
            aReferenceString = mInputRange.Format(rDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
156
0
            mxInputRangeEdit->SetRefString( aReferenceString );
157
0
        }
158
0
        else if (mpActiveEdit == mxOutputRangeEdit.get())
159
0
        {
160
0
            mOutputAddress = rReferenceRange.aStart;
161
162
0
            ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
163
0
                                                             ScRefFlags::ADDR_ABS :
164
0
                                                             ScRefFlags::ADDR_ABS_3D;
165
0
            aReferenceString = mOutputAddress.Format(nFormat, &rDocument, rDocument.GetAddressConvention());
166
0
            mxOutputRangeEdit->SetRefString( aReferenceString );
167
0
        }
168
0
    }
169
170
0
    ValidateDialogInput();
171
0
}
172
173
IMPL_LINK( ScStatisticsInputOutputDialog, ButtonClicked, weld::Button&, rButton, void )
174
0
{
175
0
    if (&rButton == mxButtonOk.get())
176
0
    {
177
0
        CalculateInputAndWriteToOutput();
178
0
        response(RET_OK);
179
0
    }
180
0
    else
181
0
        response(RET_CANCEL);
182
0
}
183
184
IMPL_LINK(ScStatisticsInputOutputDialog, GetEditFocusHandler, formula::RefEdit&, rCtrl, void)
185
0
{
186
0
    mpActiveEdit = nullptr;
187
188
0
    if (&rCtrl == mxInputRangeEdit.get())
189
0
        mpActiveEdit = mxInputRangeEdit.get();
190
0
    if (&rCtrl == mxOutputRangeEdit.get())
191
0
        mpActiveEdit = mxOutputRangeEdit.get();
192
193
0
    if (mpActiveEdit)
194
0
        mpActiveEdit->SelectAll();
195
0
}
196
197
IMPL_LINK(ScStatisticsInputOutputDialog, GetButtonFocusHandler, formula::RefButton&, rCtrl, void)
198
0
{
199
0
    mpActiveEdit = nullptr;
200
201
0
    if (&rCtrl == mxInputRangeButton.get())
202
0
        mpActiveEdit = mxInputRangeEdit.get();
203
0
    else if (&rCtrl == mxOutputRangeButton.get())
204
0
        mpActiveEdit = mxOutputRangeEdit.get();
205
206
0
    if (mpActiveEdit)
207
0
        mpActiveEdit->SelectAll();
208
0
}
209
210
IMPL_LINK_NOARG(ScStatisticsInputOutputDialog, LoseEditFocusHandler, formula::RefEdit&, void)
211
0
{
212
0
    mDialogLostFocus = !m_xDialog->has_toplevel_focus();
213
0
}
214
215
IMPL_LINK_NOARG(ScStatisticsInputOutputDialog, LoseButtonFocusHandler, formula::RefButton&, void)
216
0
{
217
0
    mDialogLostFocus = !m_xDialog->has_toplevel_focus();
218
0
}
219
220
IMPL_LINK_NOARG( ScStatisticsInputOutputDialog, GroupByChanged, weld::Toggleable&, void )
221
0
{
222
0
    if (mxGroupByColumnsRadio->get_active())
223
0
        mGroupedBy = GroupedBy::ByColumn;
224
0
    else if (mxGroupByRowsRadio->get_active())
225
0
        mGroupedBy = GroupedBy::ByRow;
226
227
0
    ValidateDialogInput();
228
0
}
229
230
IMPL_LINK_NOARG( ScStatisticsInputOutputDialog, RefInputModifyHandler, formula::RefEdit&, void )
231
0
{
232
0
    if ( mpActiveEdit )
233
0
    {
234
0
        if (mpActiveEdit == mxInputRangeEdit.get())
235
0
        {
236
0
            ScRangeList aRangeList;
237
0
            bool bValid = ParseWithNames( aRangeList, mxInputRangeEdit->GetText(), mDocument);
238
0
            const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
239
0
            if (pRange)
240
0
            {
241
0
                mInputRange = *pRange;
242
                // Highlight the resulting range.
243
0
                mxInputRangeEdit->StartUpdateData();
244
0
            }
245
0
            else
246
0
            {
247
0
                mInputRange = ScRange( ScAddress::INITIALIZE_INVALID);
248
0
            }
249
0
        }
250
0
        else if (mpActiveEdit == mxOutputRangeEdit.get())
251
0
        {
252
0
            ScRangeList aRangeList;
253
0
            bool bValid = ParseWithNames( aRangeList, mxOutputRangeEdit->GetText(), mDocument);
254
0
            const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
255
0
            if (pRange)
256
0
            {
257
0
                mOutputAddress = pRange->aStart;
258
259
                // Crop output range to top left address for Edit field.
260
0
                if (pRange->aStart != pRange->aEnd)
261
0
                {
262
0
                    ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
263
0
                                                                     ScRefFlags::ADDR_ABS :
264
0
                                                                     ScRefFlags::ADDR_ABS_3D;
265
0
                    OUString aReferenceString = mOutputAddress.Format(nFormat, &mDocument, mDocument.GetAddressConvention());
266
0
                    mxOutputRangeEdit->SetRefString( aReferenceString );
267
0
                }
268
269
                // Highlight the resulting range.
270
0
                mxOutputRangeEdit->StartUpdateData();
271
0
            }
272
0
            else
273
0
            {
274
0
                mOutputAddress = ScAddress( ScAddress::INITIALIZE_INVALID);
275
0
            }
276
0
        }
277
0
    }
278
279
0
    ValidateDialogInput();
280
0
}
281
282
void ScStatisticsInputOutputDialog::CalculateInputAndWriteToOutput()
283
0
{
284
0
    OUString aUndo(ScResId(GetUndoNameId()));
285
0
    ScDocShell* pDocShell = mViewData.GetDocShell();
286
0
    SfxUndoManager* pUndoManager = pDocShell->GetUndoManager();
287
0
    pUndoManager->EnterListAction( aUndo, aUndo, 0, mViewData.GetViewShell()->GetViewShellId() );
288
289
0
    ScRange aOutputRange = ApplyOutput(pDocShell);
290
291
0
    pUndoManager->LeaveListAction();
292
0
    pDocShell->PostPaint( aOutputRange, PaintPartFlags::Grid );
293
0
}
294
295
bool ScStatisticsInputOutputDialog::InputRangesValid()
296
0
{
297
0
    return mInputRange.IsValid() && mOutputAddress.IsValid();
298
0
}
299
300
void ScStatisticsInputOutputDialog::ValidateDialogInput()
301
0
{
302
    // Enable OK button if all inputs are ok.
303
0
    mxButtonOk->set_sensitive(InputRangesValid());
304
0
}
305
306
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */