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/dbgui/sfiltdlg.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
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <sfx2/dispatch.hxx>
21
22
#include <uiitems.hxx>
23
#include <rangenam.hxx>
24
#include <reffact.hxx>
25
#include <viewdata.hxx>
26
#include <document.hxx>
27
#include <docsh.hxx>
28
#include <scresid.hxx>
29
30
#include <foptmgr.hxx>
31
32
#include <globstr.hrc>
33
#include <strings.hrc>
34
35
#include <filtdlg.hxx>
36
#include <vcl/svapp.hxx>
37
#include <vcl/weld/Dialog.hxx>
38
#include <vcl/weld/Expander.hxx>
39
#include <vcl/weld/MessageDialog.hxx>
40
41
// DEFINE --------------------------------------------------------------------
42
43
namespace
44
{
45
    void ERRORBOX(weld::Window* pParent, TranslateId rid)
46
0
    {
47
0
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
48
0
                                                  VclMessageType::Warning, VclButtonsType::Ok,
49
0
                                                  ScResId(rid)));
50
0
        xBox->run();
51
0
    }
52
}
53
54
ScSpecialFilterDlg::ScSpecialFilterDlg(SfxBindings& rBindings, SfxChildWindow* pCW,
55
                                       weld::Window* pParent, ScViewData& rData,
56
                                       const SfxItemSet& rArgSet)
57
0
    : ScAnyRefDlgController(&rBindings, pCW, pParent,
58
0
                            u"modules/scalc/ui/advancedfilterdialog.ui"_ustr,
59
0
                            u"AdvancedFilterDialog"_ustr)
60
0
    , m_aStrUndefined(ScResId(SCSTR_UNDEFINED))
61
0
    , m_nWhichQuery(rArgSet.GetPool()->GetWhichIDFromSlotID(SID_QUERY))
62
0
    , m_theQueryData(static_cast<const ScQueryItem&>(rArgSet.Get(m_nWhichQuery)).GetQueryData())
63
0
    , m_rViewData(rData)
64
0
    , m_rDoc(m_rViewData.GetDocument())
65
0
    , m_bRefInputMode(false)
66
0
    , m_pRefInputEdit(nullptr)
67
0
    , m_xLbFilterArea(m_xBuilder->weld_combo_box(u"lbfilterarea"_ustr))
68
0
    , m_xEdFilterArea(new formula::RefEdit(m_xBuilder->weld_entry(u"edfilterarea"_ustr)))
69
0
    , m_xRbFilterArea(new formula::RefButton(m_xBuilder->weld_button(u"rbfilterarea"_ustr)))
70
0
    , m_xExpander(m_xBuilder->weld_expander(u"more"_ustr))
71
0
    , m_xBtnCase(m_xBuilder->weld_check_button(u"case"_ustr))
72
0
    , m_xBtnRegExp(m_xBuilder->weld_check_button(u"regexp"_ustr))
73
0
    , m_xBtnHeader(m_xBuilder->weld_check_button(u"header"_ustr))
74
0
    , m_xBtnUnique(m_xBuilder->weld_check_button(u"unique"_ustr))
75
0
    , m_xBtnCopyResult(m_xBuilder->weld_check_button(u"copyresult"_ustr))
76
0
    , m_xLbCopyArea(m_xBuilder->weld_combo_box(u"lbcopyarea"_ustr))
77
0
    , m_xEdCopyArea(new formula::RefEdit(m_xBuilder->weld_entry(u"edcopyarea"_ustr)))
78
0
    , m_xRbCopyArea(new formula::RefButton(m_xBuilder->weld_button(u"rbcopyarea"_ustr)))
79
0
    , m_xBtnDestPers(m_xBuilder->weld_check_button(u"destpers"_ustr))
80
0
    , m_xFtDbAreaLabel(m_xBuilder->weld_label(u"dbarealabel"_ustr))
81
0
    , m_xFtDbArea(m_xBuilder->weld_label(u"dbarea"_ustr))
82
0
    , m_xBtnOk(m_xBuilder->weld_button(u"ok"_ustr))
83
0
    , m_xBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr))
84
0
    , m_xFilterFrame(m_xBuilder->weld_frame(u"filterframe"_ustr))
85
0
{
86
0
    m_xEdFilterArea->SetReferences(this, m_xFilterFrame.get());
87
0
    m_xRbFilterArea->SetReferences(this, m_xEdFilterArea.get());
88
0
    m_xEdCopyArea->SetReferences(this, m_xFtDbAreaLabel.get());
89
0
    m_xRbCopyArea->SetReferences(this, m_xEdCopyArea.get());
90
91
0
    Init( rArgSet );
92
93
0
    Link<formula::RefEdit&, void> aLinkEdit = LINK(this, ScSpecialFilterDlg, RefInputEditHdl);
94
0
    Link<formula::RefButton&, void> aLinkButton = LINK(this, ScSpecialFilterDlg, RefInputButtonHdl);
95
0
    m_xEdCopyArea->SetGetFocusHdl(aLinkEdit);
96
0
    m_xRbCopyArea->SetGetFocusHdl(aLinkButton);
97
0
    m_xEdFilterArea->SetGetFocusHdl(aLinkEdit);
98
0
    m_xRbFilterArea->SetGetFocusHdl(aLinkButton);
99
0
    m_xEdCopyArea->SetLoseFocusHdl(aLinkEdit);
100
0
    m_xRbCopyArea->SetLoseFocusHdl(aLinkButton);
101
0
    m_xEdFilterArea->SetLoseFocusHdl(aLinkEdit);
102
0
    m_xRbFilterArea->SetLoseFocusHdl(aLinkButton);
103
104
0
    m_xEdFilterArea->GrabFocus();
105
0
}
106
107
ScSpecialFilterDlg::~ScSpecialFilterDlg()
108
0
{
109
0
    m_pOptionsMgr.reset();
110
111
0
    m_pOutItem.reset();
112
0
}
113
114
void ScSpecialFilterDlg::Init( const SfxItemSet& rArgSet )
115
0
{
116
0
    m_xBtnOk->connect_clicked( LINK( this, ScSpecialFilterDlg, EndDlgHdl ) );
117
0
    m_xBtnCancel->connect_clicked( LINK( this, ScSpecialFilterDlg, EndDlgHdl ) );
118
0
    m_xLbFilterArea->connect_changed( LINK( this, ScSpecialFilterDlg, FilterAreaSelHdl ) );
119
0
    m_xEdFilterArea->SetModifyHdl  ( LINK( this, ScSpecialFilterDlg, FilterAreaModHdl ) );
120
121
0
    m_xEdFilterArea->SetText( OUString() );      // may be overwritten below
122
123
0
    if (m_rDoc.GetChangeTrack() != nullptr)
124
0
        m_xBtnCopyResult->set_sensitive(false);
125
126
0
    ScRangeName& rRangeNames = m_rDoc.GetRangeName();
127
0
    m_xLbFilterArea->clear();
128
0
    m_xLbFilterArea->append_text(m_aStrUndefined);
129
130
0
    for (const auto& rEntry : rRangeNames)
131
0
    {
132
0
        if (!rEntry.second->HasType(ScRangeData::Type::Criteria))
133
0
            continue;
134
135
0
        OUString aSymbol = rEntry.second->GetSymbol();
136
0
        m_xLbFilterArea->append(aSymbol, rEntry.second->GetName());
137
0
    }
138
139
    //  is there a stored source range?
140
141
0
    ScRange aAdvSource;
142
0
    const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(rArgSet.Get(m_nWhichQuery));
143
144
0
    if (rQueryItem.GetAdvancedQuerySource(aAdvSource))
145
0
    {
146
0
        OUString aRefStr(
147
0
            aAdvSource.Format(m_rDoc, ScRefFlags::RANGE_ABS_3D, m_rDoc.GetAddressConvention()));
148
0
        m_xEdFilterArea->SetRefString( aRefStr );
149
0
    }
150
151
0
    m_xLbFilterArea->set_active( 0 );
152
153
    // let options be initialized:
154
155
0
    m_pOptionsMgr.reset(new ScFilterOptionsMgr(
156
0
        m_rViewData, m_theQueryData, m_xBtnCase.get(), m_xBtnRegExp.get(), m_xBtnHeader.get(),
157
0
        m_xBtnUnique.get(), m_xBtnCopyResult.get(), m_xBtnDestPers.get(), m_xLbCopyArea.get(),
158
0
        m_xEdCopyArea.get(), m_xRbCopyArea.get(), m_xFtDbAreaLabel.get(), m_xFtDbArea.get(),
159
0
        m_aStrUndefined));
160
161
    //  special filter always needs column headers
162
0
    m_xBtnHeader->set_active(true);
163
0
    m_xBtnHeader->set_sensitive(false);
164
165
    // turn on modal mode
166
    // SetDispatcherLock( true );
167
    //@BugID 54702 enable/disable in base class only
168
    //SFX_APPWINDOW->Disable(false);        //! general method in ScAnyRefDlg
169
0
}
170
171
void ScSpecialFilterDlg::Close()
172
0
{
173
0
    m_rViewData.GetDocShell()->CancelAutoDBRange();
174
175
0
    DoClose( ScSpecialFilterDlgWrapper::GetChildWindowId() );
176
0
}
177
178
// Transfer of a table area selected with the mouse, which is then displayed
179
// as a new selection in the reference edit.
180
181
void ScSpecialFilterDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
182
0
{
183
0
    if (!(m_bRefInputMode && m_pRefInputEdit)) // only possible if in the reference edit mode
184
0
        return;
185
186
0
    if ( rRef.aStart != rRef.aEnd )
187
0
        RefInputStart( m_pRefInputEdit );
188
189
0
    OUString aRefStr;
190
0
    const formula::FormulaGrammar::AddressConvention eConv = rDocP.GetAddressConvention();
191
192
0
    if (m_pRefInputEdit == m_xEdCopyArea.get())
193
0
        aRefStr = rRef.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, eConv);
194
0
    else if (m_pRefInputEdit == m_xEdFilterArea.get())
195
0
        aRefStr = rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, eConv);
196
197
0
    m_pRefInputEdit->SetRefString( aRefStr );
198
0
}
199
200
void ScSpecialFilterDlg::SetActive()
201
0
{
202
0
    if (m_bRefInputMode)
203
0
    {
204
0
        if (m_pRefInputEdit == m_xEdCopyArea.get())
205
0
        {
206
0
            m_xEdCopyArea->GrabFocus();
207
0
            m_xEdCopyArea->GetModifyHdl().Call( *m_xEdCopyArea );
208
0
        }
209
0
        else if (m_pRefInputEdit == m_xEdFilterArea.get())
210
0
        {
211
0
            m_xEdFilterArea->GrabFocus();
212
0
            FilterAreaModHdl( *m_xEdFilterArea );
213
0
        }
214
0
    }
215
0
    else
216
0
        m_xDialog->grab_focus();
217
218
0
    RefInputDone();
219
0
}
220
221
ScQueryItem* ScSpecialFilterDlg::GetOutputItem( const ScQueryParam& rParam,
222
                                                const ScRange& rSource )
223
0
{
224
0
    m_pOutItem.reset(new ScQueryItem(m_nWhichQuery, &rParam));
225
0
    m_pOutItem->SetAdvancedQuerySource(&rSource);
226
0
    return m_pOutItem.get();
227
0
}
228
229
0
bool ScSpecialFilterDlg::IsRefInputMode() const { return m_bRefInputMode; }
230
231
// Handler:
232
233
IMPL_LINK(ScSpecialFilterDlg, EndDlgHdl, weld::Button&, rBtn, void)
234
0
{
235
0
    if (&rBtn == m_xBtnOk.get())
236
0
    {
237
0
        OUString          theCopyStr( m_xEdCopyArea->GetText() );
238
0
        OUString          theAreaStr( m_xEdFilterArea->GetText() );
239
0
        ScQueryParam theOutParam(m_theQueryData);
240
0
        ScAddress       theAdrCopy;
241
0
        bool            bEditInputOk    = true;
242
0
        bool            bQueryOk        = false;
243
0
        ScRange         theFilterArea;
244
0
        const formula::FormulaGrammar::AddressConvention eConv = m_rDoc.GetAddressConvention();
245
246
0
        if ( m_xBtnCopyResult->get_active() )
247
0
        {
248
0
            sal_Int32 nColonPos = theCopyStr.indexOf( ':' );
249
250
0
            if ( -1 != nColonPos )
251
0
                theCopyStr = theCopyStr.copy( 0, nColonPos );
252
253
0
            ScRefFlags nResult = theAdrCopy.Parse(theCopyStr, m_rDoc, eConv);
254
255
0
            if ( (nResult & ScRefFlags::VALID) == ScRefFlags::ZERO )
256
0
            {
257
0
                if (!m_xExpander->get_expanded())
258
0
                    m_xExpander->set_expanded(true);
259
260
0
                ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
261
0
                m_xEdCopyArea->GrabFocus();
262
0
                bEditInputOk = false;
263
0
            }
264
0
        }
265
266
0
        if ( bEditInputOk )
267
0
        {
268
0
            ScRefFlags nResult = ScRange().Parse(theAreaStr, m_rDoc, eConv);
269
270
0
            if ( (nResult & ScRefFlags::VALID) == ScRefFlags::ZERO )
271
0
            {
272
0
                ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
273
0
                m_xEdFilterArea->GrabFocus();
274
0
                bEditInputOk = false;
275
0
            }
276
0
        }
277
278
0
        if ( bEditInputOk )
279
0
        {
280
            /*
281
             * All edit fields contain valid areas. Now try to create
282
             * an ScQueryParam from the filter area:
283
             */
284
285
0
            ScRefFlags nResult = theFilterArea.Parse(theAreaStr, m_rDoc, eConv);
286
287
0
            if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID )
288
0
            {
289
0
                ScAddress& rStart = theFilterArea.aStart;
290
0
                ScAddress& rEnd   = theFilterArea.aEnd;
291
292
0
                if ( m_xBtnCopyResult->get_active() )
293
0
                {
294
0
                    theOutParam.bInplace    = false;
295
0
                    theOutParam.nDestTab    = theAdrCopy.Tab();
296
0
                    theOutParam.nDestCol    = theAdrCopy.Col();
297
0
                    theOutParam.nDestRow    = theAdrCopy.Row();
298
0
                }
299
0
                else
300
0
                {
301
0
                    theOutParam.bInplace    = true;
302
0
                    theOutParam.nDestTab    = 0;
303
0
                    theOutParam.nDestCol    = 0;
304
0
                    theOutParam.nDestRow    = 0;
305
0
                }
306
307
0
                theOutParam.bHasHeader = m_xBtnHeader->get_active();
308
0
                theOutParam.bByRow     = true;
309
0
                theOutParam.bCaseSens  = m_xBtnCase->get_active();
310
0
                theOutParam.eSearchType = m_xBtnRegExp->get_active() ? utl::SearchParam::SearchType::Regexp :
311
0
                    utl::SearchParam::SearchType::Normal;
312
0
                theOutParam.bDuplicate = !m_xBtnUnique->get_active();
313
0
                theOutParam.bDestPers  = m_xBtnDestPers->get_active();
314
315
0
                bQueryOk = m_rDoc.CreateQueryParam(ScRange(rStart, rEnd), theOutParam);
316
0
            }
317
0
        }
318
319
0
        if ( bQueryOk )
320
0
        {
321
0
            SetDispatcherLock( false );
322
0
            SwitchToDocument();
323
0
            GetBindings().GetDispatcher()->ExecuteList(FID_FILTER_OK,
324
0
                    SfxCallMode::SLOT | SfxCallMode::RECORD,
325
0
                    { GetOutputItem(theOutParam, theFilterArea) });
326
0
            response(RET_OK);
327
0
        }
328
0
        else
329
0
        {
330
0
            ERRORBOX(m_xDialog.get(), STR_INVALID_QUERYAREA);
331
0
            m_xEdFilterArea->GrabFocus();
332
0
        }
333
0
    }
334
0
    else if (&rBtn == m_xBtnCancel.get())
335
0
    {
336
0
        response(RET_CANCEL);
337
0
    }
338
0
}
339
340
IMPL_LINK_NOARG(ScSpecialFilterDlg, RefInputEditHdl, formula::RefEdit&, void)
341
0
{
342
0
    RefInputHdl();
343
0
}
344
345
IMPL_LINK_NOARG(ScSpecialFilterDlg, RefInputButtonHdl, formula::RefButton&, void)
346
0
{
347
0
    RefInputHdl();
348
0
}
349
350
void ScSpecialFilterDlg::RefInputHdl()
351
0
{
352
0
    if (!m_xDialog->has_toplevel_focus())
353
0
        return;
354
355
0
    if( m_xEdCopyArea->GetWidget()->has_focus() || m_xRbCopyArea->GetWidget()->has_focus() )
356
0
    {
357
0
        m_pRefInputEdit = m_xEdCopyArea.get();
358
0
        m_bRefInputMode = true;
359
0
    }
360
0
    else if( m_xEdFilterArea->GetWidget()->has_focus() || m_xRbFilterArea->GetWidget()->has_focus() )
361
0
    {
362
0
        m_pRefInputEdit = m_xEdFilterArea.get();
363
0
        m_bRefInputMode = true;
364
0
    }
365
0
    else if (m_bRefInputMode)
366
0
    {
367
0
        m_pRefInputEdit = nullptr;
368
0
        m_bRefInputMode = false;
369
0
    }
370
0
}
371
372
IMPL_LINK(ScSpecialFilterDlg, FilterAreaSelHdl, weld::ComboBox&, rLb, void)
373
0
{
374
0
    if (&rLb == m_xLbFilterArea.get())
375
0
    {
376
0
        OUString  aString;
377
0
        const sal_Int32 nSelPos = m_xLbFilterArea->get_active();
378
379
0
        if ( nSelPos > 0 )
380
0
            aString = m_xLbFilterArea->get_id(nSelPos);
381
382
0
        m_xEdFilterArea->SetText( aString );
383
0
    }
384
0
}
385
386
IMPL_LINK( ScSpecialFilterDlg, FilterAreaModHdl, formula::RefEdit&, rEd, void )
387
0
{
388
0
    if (&rEd != m_xEdFilterArea.get())
389
0
        return;
390
391
0
    OUString  theCurAreaStr = rEd.GetText();
392
0
    ScRefFlags nResult = ScRange().Parse(theCurAreaStr, m_rDoc);
393
394
0
    if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID )
395
0
    {
396
0
        const sal_Int32 nCount  = m_xLbFilterArea->get_count();
397
0
        for (sal_Int32 i = 1; i < nCount; ++i)
398
0
        {
399
0
            OUString aStr = m_xLbFilterArea->get_id(i);
400
0
            if (theCurAreaStr == aStr)
401
0
            {
402
0
                m_xLbFilterArea->set_active( i );
403
0
                return;
404
0
            }
405
0
        }
406
0
        m_xLbFilterArea->set_active( 0 );
407
0
    }
408
0
}
409
410
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */