Coverage Report

Created: 2026-03-31 11:00

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/MessageDialog.hxx>
39
#include <vcl/weld/weld.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
55
ScSpecialFilterDlg::ScSpecialFilterDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
56
                                        ScViewData& rData, const SfxItemSet&   rArgSet )
57
58
0
    : ScAnyRefDlgController(pB, pCW, pParent, u"modules/scalc/ui/advancedfilterdialog.ui"_ustr, u"AdvancedFilterDialog"_ustr)
59
0
    , aStrUndefined   ( ScResId(SCSTR_UNDEFINED) )
60
0
    , nWhichQuery     ( rArgSet.GetPool()->GetWhichIDFromSlotID( SID_QUERY ) )
61
0
    , theQueryData    ( static_cast<const ScQueryItem&>(
62
0
                           rArgSet.Get( nWhichQuery )).GetQueryData() )
63
0
    , rViewData(rData)
64
0
    , rDoc(rViewData.GetDocument())
65
0
    , 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
    pOptionsMgr.reset();
110
111
0
    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(rDoc.GetChangeTrack()!=nullptr) m_xBtnCopyResult->set_sensitive(false);
124
125
0
    ScRangeName* pRangeNames = rDoc.GetRangeName();
126
0
    m_xLbFilterArea->clear();
127
0
    m_xLbFilterArea->append_text(aStrUndefined);
128
129
0
    for (const auto& rEntry : *pRangeNames)
130
0
    {
131
0
        if (!rEntry.second->HasType(ScRangeData::Type::Criteria))
132
0
            continue;
133
134
0
        OUString aSymbol = rEntry.second->GetSymbol();
135
0
        m_xLbFilterArea->append(aSymbol, rEntry.second->GetName());
136
0
    }
137
138
    //  is there a stored source range?
139
140
0
    ScRange aAdvSource;
141
0
    const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(
142
0
                                    rArgSet.Get( nWhichQuery ));
143
144
0
    if (rQueryItem.GetAdvancedQuerySource(aAdvSource))
145
0
    {
146
0
        OUString aRefStr(aAdvSource.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
147
0
        m_xEdFilterArea->SetRefString( aRefStr );
148
0
    }
149
150
0
    m_xLbFilterArea->set_active( 0 );
151
152
    // let options be initialized:
153
154
0
    pOptionsMgr.reset( new ScFilterOptionsMgr(
155
0
                            rViewData,
156
0
                            theQueryData,
157
0
                            m_xBtnCase.get(),
158
0
                            m_xBtnRegExp.get(),
159
0
                            m_xBtnHeader.get(),
160
0
                            m_xBtnUnique.get(),
161
0
                            m_xBtnCopyResult.get(),
162
0
                            m_xBtnDestPers.get(),
163
0
                            m_xLbCopyArea.get(),
164
0
                            m_xEdCopyArea.get(),
165
0
                            m_xRbCopyArea.get(),
166
0
                            m_xFtDbAreaLabel.get(),
167
0
                            m_xFtDbArea.get(),
168
0
                            aStrUndefined ) );
169
170
    //  special filter always needs column headers
171
0
    m_xBtnHeader->set_active(true);
172
0
    m_xBtnHeader->set_sensitive(false);
173
174
    // turn on modal mode
175
    // SetDispatcherLock( true );
176
    //@BugID 54702 enable/disable in base class only
177
    //SFX_APPWINDOW->Disable(false);        //! general method in ScAnyRefDlg
178
0
}
179
180
void ScSpecialFilterDlg::Close()
181
0
{
182
0
    rViewData.GetDocShell()->CancelAutoDBRange();
183
184
0
    DoClose( ScSpecialFilterDlgWrapper::GetChildWindowId() );
185
0
}
186
187
// Transfer of a table area selected with the mouse, which is then displayed
188
// as a new selection in the reference edit.
189
190
void ScSpecialFilterDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
191
0
{
192
0
    if ( !(bRefInputMode && m_pRefInputEdit) )       // only possible if in the reference edit mode
193
0
        return;
194
195
0
    if ( rRef.aStart != rRef.aEnd )
196
0
        RefInputStart( m_pRefInputEdit );
197
198
0
    OUString aRefStr;
199
0
    const formula::FormulaGrammar::AddressConvention eConv = rDocP.GetAddressConvention();
200
201
0
    if (m_pRefInputEdit == m_xEdCopyArea.get())
202
0
        aRefStr = rRef.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, eConv);
203
0
    else if (m_pRefInputEdit == m_xEdFilterArea.get())
204
0
        aRefStr = rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, eConv);
205
206
0
    m_pRefInputEdit->SetRefString( aRefStr );
207
0
}
208
209
void ScSpecialFilterDlg::SetActive()
210
0
{
211
0
    if ( bRefInputMode )
212
0
    {
213
0
        if (m_pRefInputEdit == m_xEdCopyArea.get())
214
0
        {
215
0
            m_xEdCopyArea->GrabFocus();
216
0
            m_xEdCopyArea->GetModifyHdl().Call( *m_xEdCopyArea );
217
0
        }
218
0
        else if (m_pRefInputEdit == m_xEdFilterArea.get())
219
0
        {
220
0
            m_xEdFilterArea->GrabFocus();
221
0
            FilterAreaModHdl( *m_xEdFilterArea );
222
0
        }
223
0
    }
224
0
    else
225
0
        m_xDialog->grab_focus();
226
227
0
    RefInputDone();
228
0
}
229
230
ScQueryItem* ScSpecialFilterDlg::GetOutputItem( const ScQueryParam& rParam,
231
                                                const ScRange& rSource )
232
0
{
233
0
    pOutItem.reset(new ScQueryItem( nWhichQuery, &rParam ));
234
0
    pOutItem->SetAdvancedQuerySource( &rSource );
235
0
    return pOutItem.get();
236
0
}
237
238
bool ScSpecialFilterDlg::IsRefInputMode() const
239
0
{
240
0
    return bRefInputMode;
241
0
}
242
243
// Handler:
244
245
IMPL_LINK(ScSpecialFilterDlg, EndDlgHdl, weld::Button&, rBtn, void)
246
0
{
247
0
    if (&rBtn == m_xBtnOk.get())
248
0
    {
249
0
        OUString          theCopyStr( m_xEdCopyArea->GetText() );
250
0
        OUString          theAreaStr( m_xEdFilterArea->GetText() );
251
0
        ScQueryParam    theOutParam( theQueryData );
252
0
        ScAddress       theAdrCopy;
253
0
        bool            bEditInputOk    = true;
254
0
        bool            bQueryOk        = false;
255
0
        ScRange         theFilterArea;
256
0
        const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
257
258
0
        if ( m_xBtnCopyResult->get_active() )
259
0
        {
260
0
            sal_Int32 nColonPos = theCopyStr.indexOf( ':' );
261
262
0
            if ( -1 != nColonPos )
263
0
                theCopyStr = theCopyStr.copy( 0, nColonPos );
264
265
0
            ScRefFlags nResult = theAdrCopy.Parse( theCopyStr, rDoc, eConv );
266
267
0
            if ( (nResult & ScRefFlags::VALID) == ScRefFlags::ZERO )
268
0
            {
269
0
                if (!m_xExpander->get_expanded())
270
0
                    m_xExpander->set_expanded(true);
271
272
0
                ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
273
0
                m_xEdCopyArea->GrabFocus();
274
0
                bEditInputOk = false;
275
0
            }
276
0
        }
277
278
0
        if ( bEditInputOk )
279
0
        {
280
0
            ScRefFlags nResult = ScRange().Parse( theAreaStr, rDoc, eConv );
281
282
0
            if ( (nResult & ScRefFlags::VALID) == ScRefFlags::ZERO )
283
0
            {
284
0
                ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
285
0
                m_xEdFilterArea->GrabFocus();
286
0
                bEditInputOk = false;
287
0
            }
288
0
        }
289
290
0
        if ( bEditInputOk )
291
0
        {
292
            /*
293
             * All edit fields contain valid areas. Now try to create
294
             * a ScQueryParam from the filter area:
295
             */
296
297
0
            ScRefFlags  nResult = theFilterArea.Parse( theAreaStr, rDoc, eConv );
298
299
0
            if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID )
300
0
            {
301
0
                ScAddress& rStart = theFilterArea.aStart;
302
0
                ScAddress& rEnd   = theFilterArea.aEnd;
303
304
0
                if ( m_xBtnCopyResult->get_active() )
305
0
                {
306
0
                    theOutParam.bInplace    = false;
307
0
                    theOutParam.nDestTab    = theAdrCopy.Tab();
308
0
                    theOutParam.nDestCol    = theAdrCopy.Col();
309
0
                    theOutParam.nDestRow    = theAdrCopy.Row();
310
0
                }
311
0
                else
312
0
                {
313
0
                    theOutParam.bInplace    = true;
314
0
                    theOutParam.nDestTab    = 0;
315
0
                    theOutParam.nDestCol    = 0;
316
0
                    theOutParam.nDestRow    = 0;
317
0
                }
318
319
0
                theOutParam.bHasHeader = m_xBtnHeader->get_active();
320
0
                theOutParam.bByRow     = true;
321
0
                theOutParam.bCaseSens  = m_xBtnCase->get_active();
322
0
                theOutParam.eSearchType = m_xBtnRegExp->get_active() ? utl::SearchParam::SearchType::Regexp :
323
0
                    utl::SearchParam::SearchType::Normal;
324
0
                theOutParam.bDuplicate = !m_xBtnUnique->get_active();
325
0
                theOutParam.bDestPers  = m_xBtnDestPers->get_active();
326
327
0
                bQueryOk = rDoc.CreateQueryParam(ScRange(rStart,rEnd), theOutParam);
328
0
            }
329
0
        }
330
331
0
        if ( bQueryOk )
332
0
        {
333
0
            SetDispatcherLock( false );
334
0
            SwitchToDocument();
335
0
            GetBindings().GetDispatcher()->ExecuteList(FID_FILTER_OK,
336
0
                    SfxCallMode::SLOT | SfxCallMode::RECORD,
337
0
                    { GetOutputItem(theOutParam, theFilterArea) });
338
0
            response(RET_OK);
339
0
        }
340
0
        else
341
0
        {
342
0
            ERRORBOX(m_xDialog.get(), STR_INVALID_QUERYAREA);
343
0
            m_xEdFilterArea->GrabFocus();
344
0
        }
345
0
    }
346
0
    else if (&rBtn == m_xBtnCancel.get())
347
0
    {
348
0
        response(RET_CANCEL);
349
0
    }
350
0
}
351
352
IMPL_LINK_NOARG(ScSpecialFilterDlg, RefInputEditHdl, formula::RefEdit&, void)
353
0
{
354
0
    RefInputHdl();
355
0
}
356
357
IMPL_LINK_NOARG(ScSpecialFilterDlg, RefInputButtonHdl, formula::RefButton&, void)
358
0
{
359
0
    RefInputHdl();
360
0
}
361
362
void ScSpecialFilterDlg::RefInputHdl()
363
0
{
364
0
    if (!m_xDialog->has_toplevel_focus())
365
0
        return;
366
367
0
    if( m_xEdCopyArea->GetWidget()->has_focus() || m_xRbCopyArea->GetWidget()->has_focus() )
368
0
    {
369
0
        m_pRefInputEdit = m_xEdCopyArea.get();
370
0
        bRefInputMode = true;
371
0
    }
372
0
    else if( m_xEdFilterArea->GetWidget()->has_focus() || m_xRbFilterArea->GetWidget()->has_focus() )
373
0
    {
374
0
        m_pRefInputEdit = m_xEdFilterArea.get();
375
0
        bRefInputMode = true;
376
0
    }
377
0
    else if( bRefInputMode )
378
0
    {
379
0
        m_pRefInputEdit = nullptr;
380
0
        bRefInputMode = false;
381
0
    }
382
0
}
383
384
IMPL_LINK(ScSpecialFilterDlg, FilterAreaSelHdl, weld::ComboBox&, rLb, void)
385
0
{
386
0
    if (&rLb == m_xLbFilterArea.get())
387
0
    {
388
0
        OUString  aString;
389
0
        const sal_Int32 nSelPos = m_xLbFilterArea->get_active();
390
391
0
        if ( nSelPos > 0 )
392
0
            aString = m_xLbFilterArea->get_id(nSelPos);
393
394
0
        m_xEdFilterArea->SetText( aString );
395
0
    }
396
0
}
397
398
IMPL_LINK( ScSpecialFilterDlg, FilterAreaModHdl, formula::RefEdit&, rEd, void )
399
0
{
400
0
    if (&rEd != m_xEdFilterArea.get())
401
0
        return;
402
403
0
    OUString  theCurAreaStr = rEd.GetText();
404
0
    ScRefFlags  nResult = ScRange().Parse( theCurAreaStr, rDoc );
405
406
0
    if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID )
407
0
    {
408
0
        const sal_Int32 nCount  = m_xLbFilterArea->get_count();
409
0
        for (sal_Int32 i = 1; i < nCount; ++i)
410
0
        {
411
0
            OUString aStr = m_xLbFilterArea->get_id(i);
412
0
            if (theCurAreaStr == aStr)
413
0
            {
414
0
                m_xLbFilterArea->set_active( i );
415
0
                return;
416
0
            }
417
0
        }
418
0
        m_xLbFilterArea->set_active( 0 );
419
0
    }
420
0
}
421
422
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */