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 #include <sal/log.hxx>
22 
23 #include <uiitems.hxx>
24 #include <reffact.hxx>
25 #include <viewdata.hxx>
26 #include <document.hxx>
27 #include <docsh.hxx>
28 #include <scresid.hxx>
29 #include <queryentry.hxx>
30 
31 #include <foptmgr.hxx>
32 
33 #include <globstr.hrc>
34 #include <strings.hrc>
35 
36 #include <filtdlg.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/weld.hxx>
39 #include <svl/sharedstringpool.hxx>
40 
41 #include <limits>
42 
43 #define QUERY_ENTRY_COUNT 4
44 #define INVALID_HEADER_POS std::numeric_limits<size_t>::max()
45 
EntryList()46 ScFilterDlg::EntryList::EntryList() :
47     mnHeaderPos(INVALID_HEADER_POS) {}
48 
ScFilterDlg(SfxBindings * pB,SfxChildWindow * pCW,weld::Window * pParent,const SfxItemSet & rArgSet)49 ScFilterDlg::ScFilterDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
50     const SfxItemSet& rArgSet)
51     : ScAnyRefDlgController(pB, pCW, pParent,
52         "modules/scalc/ui/standardfilterdialog.ui", "StandardFilterDialog")
53     , aStrUndefined(ScResId(SCSTR_UNDEFINED))
54     , aStrNone(ScResId(SCSTR_NONE))
55     , aStrEmpty(ScResId(SCSTR_FILTER_EMPTY))
56     , aStrNotEmpty(ScResId(SCSTR_FILTER_NOTEMPTY))
57     , aStrColumn(ScResId(SCSTR_COLUMN))
58     , nWhichQuery(rArgSet.GetPool()->GetWhich(SID_QUERY))
59     , theQueryData(static_cast<const ScQueryItem&>(rArgSet.Get(nWhichQuery)).GetQueryData())
60     , pViewData(nullptr)
61     , pDoc(nullptr)
62     , nSrcTab(0)
63     , bRefInputMode(false)
64     , m_xLbConnect1(m_xBuilder->weld_combo_box("connect1"))
65     , m_xLbField1(m_xBuilder->weld_combo_box("field1"))
66     , m_xLbCond1(m_xBuilder->weld_combo_box("cond1"))
67     , m_xEdVal1(m_xBuilder->weld_combo_box("val1"))
68     , m_xBtnRemove1(m_xBuilder->weld_button("remove1"))
69     , m_xLbConnect2(m_xBuilder->weld_combo_box("connect2"))
70     , m_xLbField2(m_xBuilder->weld_combo_box("field2"))
71     , m_xLbCond2(m_xBuilder->weld_combo_box("cond2"))
72     , m_xEdVal2(m_xBuilder->weld_combo_box("val2"))
73     , m_xBtnRemove2(m_xBuilder->weld_button("remove2"))
74     , m_xLbConnect3(m_xBuilder->weld_combo_box("connect3"))
75     , m_xLbField3(m_xBuilder->weld_combo_box("field3"))
76     , m_xLbCond3(m_xBuilder->weld_combo_box("cond3"))
77     , m_xEdVal3(m_xBuilder->weld_combo_box("val3"))
78     , m_xBtnRemove3(m_xBuilder->weld_button("remove3"))
79     , m_xLbConnect4(m_xBuilder->weld_combo_box("connect4"))
80     , m_xLbField4(m_xBuilder->weld_combo_box("field4"))
81     , m_xLbCond4(m_xBuilder->weld_combo_box("cond4"))
82     , m_xEdVal4(m_xBuilder->weld_combo_box("val4"))
83     , m_xBtnRemove4(m_xBuilder->weld_button("remove4"))
84     , m_xContents(m_xBuilder->weld_widget("grid"))
85     , m_xScrollBar(m_xBuilder->weld_scrolled_window("scrollbar", true))
86     , m_xExpander(m_xBuilder->weld_expander("more"))
87     , m_xBtnClear(m_xBuilder->weld_button("clear"))
88     , m_xBtnOk(m_xBuilder->weld_button("ok"))
89     , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
90     , m_xBtnCase(m_xBuilder->weld_check_button("case"))
91     , m_xBtnRegExp(m_xBuilder->weld_check_button("regexp"))
92     , m_xBtnHeader(m_xBuilder->weld_check_button("header"))
93     , m_xBtnUnique(m_xBuilder->weld_check_button("unique"))
94     , m_xBtnCopyResult(m_xBuilder->weld_check_button("copyresult"))
95     , m_xLbCopyArea(m_xBuilder->weld_combo_box("lbcopyarea"))
96     , m_xEdCopyArea(new formula::RefEdit(m_xBuilder->weld_entry("edcopyarea")))
97     , m_xRbCopyArea(new formula::RefButton(m_xBuilder->weld_button("rbcopyarea")))
98     , m_xBtnDestPers(m_xBuilder->weld_check_button("destpers"))
99     , m_xFtDbAreaLabel(m_xBuilder->weld_label("dbarealabel"))
100     , m_xFtDbArea(m_xBuilder->weld_label("dbarea"))
101 {
102     m_xExpander->connect_expanded(LINK(this, ScFilterDlg, MoreExpandedHdl));
103     m_xEdCopyArea->SetReferences(this, m_xFtDbAreaLabel.get());
104     m_xRbCopyArea->SetReferences(this, m_xEdCopyArea.get());
105 
106     Init( rArgSet );
107 
108     // Hack: RefInput control
109     pTimer.reset( new Timer("ScFilterTimer") );
110     pTimer->SetTimeout( 50 ); // Wait 50ms
111     pTimer->SetInvokeHandler( LINK( this, ScFilterDlg, TimeOutHdl ) );
112 }
113 
~ScFilterDlg()114 ScFilterDlg::~ScFilterDlg()
115 {
116     pOptionsMgr.reset();
117     pOutItem.reset();
118 
119     // Hack: RefInput control
120     pTimer->Stop();
121     pTimer.reset();
122 }
123 
Init(const SfxItemSet & rArgSet)124 void ScFilterDlg::Init( const SfxItemSet& rArgSet )
125 {
126     const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(
127                                     rArgSet.Get( nWhichQuery ));
128 
129     m_xBtnClear->connect_clicked   ( LINK( this, ScFilterDlg, BtnClearHdl ) );
130     m_xBtnOk->connect_clicked      ( LINK( this, ScFilterDlg, EndDlgHdl ) );
131     m_xBtnCancel->connect_clicked  ( LINK( this, ScFilterDlg, EndDlgHdl ) );
132     m_xBtnHeader->connect_toggled  ( LINK( this, ScFilterDlg, CheckBoxHdl ) );
133     m_xBtnCase->connect_toggled    ( LINK( this, ScFilterDlg, CheckBoxHdl ) );
134 
135     m_xLbField1->connect_changed  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
136     m_xLbField2->connect_changed  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
137     m_xLbField3->connect_changed  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
138     m_xLbField4->connect_changed  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
139     m_xLbConnect1->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
140     m_xLbConnect2->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
141     m_xLbConnect3->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
142     m_xLbConnect4->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
143 
144     m_xLbField1->append_text("0000000000");
145     m_xLbField1->set_active(0);
146     auto nPrefWidth = m_xLbField1->get_preferred_size().Width();
147     m_xLbField1->clear();
148 
149     m_xLbField1->set_size_request(nPrefWidth, -1);
150     m_xLbField2->set_size_request(nPrefWidth, -1);
151     m_xLbField3->set_size_request(nPrefWidth, -1);
152     m_xLbField4->set_size_request(nPrefWidth, -1);
153 
154     m_xLbCond1->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
155     m_xLbCond2->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
156     m_xLbCond3->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
157     m_xLbCond4->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
158 
159     m_xBtnRemove1->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
160     m_xBtnRemove2->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
161     m_xBtnRemove3->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
162     m_xBtnRemove4->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
163 
164     pViewData   = rQueryItem.GetViewData();
165     pDoc        = pViewData ? &pViewData->GetDocument() : nullptr;
166     nSrcTab     = pViewData ? pViewData->GetTabNo() : static_cast<SCTAB>(0);
167 
168     // for easier access:
169     maFieldLbArr.reserve(QUERY_ENTRY_COUNT);
170     maFieldLbArr.push_back(m_xLbField1.get());
171     maFieldLbArr.push_back(m_xLbField2.get());
172     maFieldLbArr.push_back(m_xLbField3.get());
173     maFieldLbArr.push_back(m_xLbField4.get());
174     maValueEdArr.reserve(QUERY_ENTRY_COUNT);
175     maValueEdArr.push_back(m_xEdVal1.get());
176     maValueEdArr.push_back(m_xEdVal2.get());
177     maValueEdArr.push_back(m_xEdVal3.get());
178     maValueEdArr.push_back(m_xEdVal4.get());
179     maCondLbArr.reserve(QUERY_ENTRY_COUNT);
180     maCondLbArr.push_back(m_xLbCond1.get());
181     maCondLbArr.push_back(m_xLbCond2.get());
182     maCondLbArr.push_back(m_xLbCond3.get());
183     maCondLbArr.push_back(m_xLbCond4.get());
184     maConnLbArr.reserve(QUERY_ENTRY_COUNT);
185     maConnLbArr.push_back(m_xLbConnect1.get());
186     maConnLbArr.push_back(m_xLbConnect2.get());
187     maConnLbArr.push_back(m_xLbConnect3.get());
188     maConnLbArr.push_back(m_xLbConnect4.get());
189     maRemoveBtnArr.reserve(QUERY_ENTRY_COUNT);
190     maRemoveBtnArr.push_back(m_xBtnRemove1.get());
191     maRemoveBtnArr.push_back(m_xBtnRemove2.get());
192     maRemoveBtnArr.push_back(m_xBtnRemove3.get());
193     maRemoveBtnArr.push_back(m_xBtnRemove4.get());
194 
195     // Option initialization:
196     pOptionsMgr.reset( new ScFilterOptionsMgr(
197                             pViewData,
198                             theQueryData,
199                             m_xBtnCase.get(),
200                             m_xBtnRegExp.get(),
201                             m_xBtnHeader.get(),
202                             m_xBtnUnique.get(),
203                             m_xBtnCopyResult.get(),
204                             m_xBtnDestPers.get(),
205                             m_xLbCopyArea.get(),
206                             m_xEdCopyArea.get(),
207                             m_xRbCopyArea.get(),
208                             m_xFtDbAreaLabel.get(),
209                             m_xFtDbArea.get(),
210                             aStrUndefined ) );
211     // Read in field lists and select entries
212 
213     FillFieldLists();
214 
215     for (size_t i = 0; i < QUERY_ENTRY_COUNT; ++i)
216     {
217         OUString aValStr;
218         size_t nCondPos = 0;
219         size_t nFieldSelPos = 0;
220 
221         ScQueryEntry& rEntry = theQueryData.GetEntry(i);
222         if ( rEntry.bDoQuery )
223         {
224             nCondPos = static_cast<size_t>(rEntry.eOp);
225             nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );
226             if (rEntry.IsQueryByEmpty())
227             {
228                 aValStr = aStrEmpty;
229                 maCondLbArr[i]->set_sensitive(false);
230             }
231             else if (rEntry.IsQueryByNonEmpty())
232             {
233                 aValStr = aStrNotEmpty;
234                 maCondLbArr[i]->set_sensitive(false);
235             }
236             else if (rEntry.IsQueryByTextColor() || rEntry.IsQueryByBackgroundColor())
237             {
238                 // No support for color filters in filter dialog currently
239                 continue;
240             }
241             else
242             {
243                 const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
244                 OUString aQueryStr = rItem.maString.getString();
245                 SetValString(aQueryStr, rItem, aValStr);
246             }
247         }
248         else if ( i == 0 )
249         {
250             nFieldSelPos = pViewData ? GetFieldSelPos(pViewData->GetCurX()) : 0;
251             rEntry.nField = nFieldSelPos ? (theQueryData.nCol1 +
252                 static_cast<SCCOL>(nFieldSelPos) - 1) : static_cast<SCCOL>(0);
253             rEntry.bDoQuery=true;
254             if (maRefreshExceptQuery.size() < i + 1)
255                 maRefreshExceptQuery.resize(i + 1, false);
256             maRefreshExceptQuery[i] = true;
257 
258         }
259         maFieldLbArr[i]->set_active( nFieldSelPos );
260         maCondLbArr [i]->set_active( nCondPos );
261         maValueEdArr[i]->set_entry_text( aValStr );
262         maValueEdArr[i]->set_entry_completion(false);
263         maValueEdArr[i]->connect_changed( LINK( this, ScFilterDlg, ValModifyHdl ) );
264         UpdateValueList(i+1);
265     }
266 
267     m_xScrollBar->connect_vadjustment_changed( LINK( this, ScFilterDlg, ScrollHdl ) );
268     m_xScrollBar->vadjustment_configure(0, 0, 8, 1, 3, 4);
269     Size aSize(m_xContents->get_preferred_size());
270     m_xContents->set_size_request(aSize.Width(), aSize.Height());
271 
272     m_xLbConnect1->hide();
273     // Disable/Enable Logic:
274 
275     (m_xLbField1->get_active() != 0)
276     && (m_xLbField2->get_active() != 0)
277         ? m_xLbConnect2->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(1).eConnect) )
278         : m_xLbConnect2->set_active(-1);
279 
280     (m_xLbField2->get_active() != 0)
281     && (m_xLbField3->get_active() != 0)
282         ? m_xLbConnect3->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(2).eConnect) )
283         : m_xLbConnect3->set_active(-1);
284 
285     (m_xLbField3->get_active() != 0)
286     && (m_xLbField4->get_active() != 0)
287         ? m_xLbConnect4->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(3).eConnect) )
288         : m_xLbConnect4->set_active(-1);
289     if ( m_xLbField1->get_active() == 0 )
290     {
291         m_xLbConnect2->set_sensitive(false);
292         m_xLbField2->set_sensitive(false);
293         m_xLbCond2->set_sensitive(false);
294         m_xEdVal2->set_sensitive(false);
295         m_xBtnRemove2->set_sensitive(false);
296     }
297     else if ( m_xLbConnect2->get_active() == -1 )
298     {
299         m_xLbField2->set_sensitive(false);
300         m_xLbCond2->set_sensitive(false);
301         m_xEdVal2->set_sensitive(false);
302         m_xBtnRemove2->set_sensitive(false);
303     }
304 
305     if ( m_xLbField2->get_active() == 0 )
306     {
307         m_xLbConnect3->set_sensitive(false);
308         m_xLbField3->set_sensitive(false);
309         m_xLbCond3->set_sensitive(false);
310         m_xEdVal3->set_sensitive(false);
311         m_xBtnRemove3->set_sensitive(false);
312     }
313     else if ( m_xLbConnect3->get_active() == -1 )
314     {
315         m_xLbField3->set_sensitive(false);
316         m_xLbCond3->set_sensitive(false);
317         m_xEdVal3->set_sensitive(false);
318         m_xBtnRemove3->set_sensitive(false);
319     }
320     if ( m_xLbField3->get_active() == 0 )
321     {
322         m_xLbConnect4->set_sensitive(false);
323         m_xLbField4->set_sensitive(false);
324         m_xLbCond4->set_sensitive(false);
325         m_xEdVal4->set_sensitive(false);
326         m_xBtnRemove4->set_sensitive(false);
327     }
328     else if ( m_xLbConnect4->get_active() == -1 )
329     {
330         m_xLbField4->set_sensitive(false);
331         m_xLbCond4->set_sensitive(false);
332         m_xEdVal4->set_sensitive(false);
333         m_xBtnRemove4->set_sensitive(false);
334     }
335 
336     m_xEdVal1->set_entry_width_chars(10);
337     m_xEdVal2->set_entry_width_chars(10);
338     m_xEdVal3->set_entry_width_chars(10);
339     m_xEdVal4->set_entry_width_chars(10);
340 
341     if (pDoc != nullptr && pDoc->GetChangeTrack() != nullptr)
342         m_xBtnCopyResult->set_sensitive(false);
343 }
344 
Close()345 void ScFilterDlg::Close()
346 {
347     if (pViewData)
348         pViewData->GetDocShell()->CancelAutoDBRange();
349 
350     DoClose( ScFilterDlgWrapper::GetChildWindowId() );
351 }
352 
353 // Mouse-selected cell area becomes the new selection and is shown in the
354 // reference text box
355 
SetReference(const ScRange & rRef,ScDocument & rDocP)356 void ScFilterDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
357 {
358     if ( bRefInputMode )    // Only possible if in reference edit mode
359     {
360         if ( rRef.aStart != rRef.aEnd )
361             RefInputStart( m_xEdCopyArea.get() );
362         OUString aRefStr(rRef.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, rDocP.GetAddressConvention()));
363         m_xEdCopyArea->SetRefString( aRefStr );
364     }
365 }
366 
SetActive()367 void ScFilterDlg::SetActive()
368 {
369     if ( bRefInputMode )
370     {
371         m_xEdCopyArea->GrabFocus();
372         m_xEdCopyArea->GetModifyHdl().Call( *m_xEdCopyArea );
373     }
374     else
375         m_xDialog->grab_focus();
376 
377     RefInputDone();
378 }
379 
FillFieldLists()380 void ScFilterDlg::FillFieldLists()
381 {
382     m_xLbField1->freeze();
383     m_xLbField2->freeze();
384     m_xLbField3->freeze();
385     m_xLbField4->freeze();
386 
387     m_xLbField1->clear();
388     m_xLbField2->clear();
389     m_xLbField3->clear();
390     m_xLbField4->clear();
391     m_xLbField1->append_text( aStrNone );
392     m_xLbField2->append_text( aStrNone );
393     m_xLbField3->append_text( aStrNone );
394     m_xLbField4->append_text( aStrNone );
395 
396     if ( pDoc )
397     {
398         OUString aFieldName;
399         SCTAB   nTab        = nSrcTab;
400         SCCOL   nFirstCol   = theQueryData.nCol1;
401         SCROW   nFirstRow   = theQueryData.nRow1;
402         SCCOL   nMaxCol     = theQueryData.nCol2;
403         SCCOL   col = 0;
404 
405         for ( col=nFirstCol; col<=nMaxCol; col++ )
406         {
407             aFieldName = pDoc->GetString(col, nFirstRow, nTab);
408             if (!m_xBtnHeader->get_active() || aFieldName.isEmpty())
409             {
410                 aFieldName = ScGlobal::ReplaceOrAppend( aStrColumn, u"%1", ScColToAlpha( col ));
411             }
412             m_xLbField1->append_text( aFieldName );
413             m_xLbField2->append_text( aFieldName );
414             m_xLbField3->append_text( aFieldName );
415             m_xLbField4->append_text( aFieldName );
416         }
417     }
418 
419     m_xLbField4->thaw();
420     m_xLbField3->thaw();
421     m_xLbField2->thaw();
422     m_xLbField1->thaw();
423 }
424 
UpdateValueList(size_t nList)425 void ScFilterDlg::UpdateValueList( size_t nList )
426 {
427     bool bCaseSens = m_xBtnCase->get_active();
428 
429     if (pDoc && nList > 0 && nList <= QUERY_ENTRY_COUNT)
430     {
431         weld::ComboBox* pValList = maValueEdArr[nList-1];
432         const sal_Int32 nFieldSelPos = maFieldLbArr[nList-1]->get_active();
433         OUString aCurValue = pValList->get_active_text();
434 
435         std::unique_ptr<weld::WaitObject> xWaiter;
436         std::vector<weld::ComboBoxEntry> aEntries;
437         aEntries.emplace_back(aStrNotEmpty);
438         aEntries.emplace_back(aStrEmpty);
439 
440         if (nFieldSelPos)
441         {
442             xWaiter.reset(new weld::WaitObject(m_xDialog.get()));     // even if only the list box has content
443             SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
444             EntryList* pList = nullptr;
445             if (!m_EntryLists.count(nColumn))
446             {
447                 size_t nOffset = GetSliderPos();
448                 SCTAB nTab       = nSrcTab;
449                 SCROW nFirstRow = theQueryData.nRow1;
450                 SCROW nLastRow   = theQueryData.nRow2;
451                 if (maHasDates.size() < nOffset+nList)
452                     maHasDates.resize(nOffset+nList, false);
453                 maHasDates[nOffset+nList-1] = false;
454 
455                 // first without the first line
456                 std::pair<EntryListsMap::iterator, bool> r =
457                     m_EntryLists.insert(std::make_pair(nColumn, std::make_unique<EntryList>()));
458                 if (!r.second)
459                     // insertion failed.
460                     return;
461 
462                 pList = r.first->second.get();
463                 pDoc->GetFilterEntriesArea(
464                     nColumn, nFirstRow+1, nLastRow,
465                     nTab, bCaseSens, pList->maFilterEntries);
466                 maHasDates[nOffset+nList-1] = pList->maFilterEntries.mbHasDates;
467 
468                 // Entry for the first line
469                 //! Entry (pHdrEntry) doesn't generate collection?
470 
471                 pList->mnHeaderPos = INVALID_HEADER_POS;
472                 ScFilterEntries aHdrColl;
473                 pDoc->GetFilterEntriesArea(
474                     nColumn, nFirstRow, nFirstRow, nTab, true, aHdrColl );
475                 if (!aHdrColl.empty())
476                 {
477                     // See if the header value is already in the list.
478                     std::vector<ScTypedStrData>::iterator itBeg = pList->maFilterEntries.begin(), itEnd = pList->maFilterEntries.end();
479                     if (std::none_of(itBeg, itEnd, FindTypedStrData(aHdrColl.front(), bCaseSens)))
480                     {
481                         // Not in the list. Insert it.
482                         pList->maFilterEntries.push_back(aHdrColl.front());
483                         if (bCaseSens)
484                             std::sort(pList->maFilterEntries.begin(), pList->maFilterEntries.end(), ScTypedStrData::LessCaseSensitive());
485                         else
486                             std::sort(pList->maFilterEntries.begin(), pList->maFilterEntries.end(), ScTypedStrData::LessCaseInsensitive());
487 
488                         // Record its position.
489                         itBeg = pList->maFilterEntries.begin();
490                         itEnd = pList->maFilterEntries.end();
491                         auto it = std::find_if(itBeg, itEnd, FindTypedStrData(aHdrColl.front(), bCaseSens));
492                         pList->mnHeaderPos = std::distance(itBeg, it);
493                     }
494                 }
495             }
496             else
497                 pList = m_EntryLists[nColumn].get();
498 
499             assert(pList);
500 
501             for (const auto& rEntry : pList->maFilterEntries)
502                 aEntries.emplace_back(rEntry.GetString());
503         }
504         pValList->insert_vector(aEntries, false);
505         pValList->set_entry_text(aCurValue);
506     }
507 
508     UpdateHdrInValueList( nList );
509 }
510 
UpdateHdrInValueList(size_t nList)511 void ScFilterDlg::UpdateHdrInValueList( size_t nList )
512 {
513     //! GetText / SetText ??
514 
515     if (!pDoc)
516         return;
517 
518     if (nList == 0 || nList > QUERY_ENTRY_COUNT)
519         return;
520 
521     size_t nFieldSelPos = maFieldLbArr[nList-1]->get_active();
522     if (!nFieldSelPos)
523         return;
524 
525     SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
526     if (!m_EntryLists.count(nColumn))
527     {
528         OSL_FAIL("column not yet initialized");
529         return;
530     }
531 
532     size_t const nPos = m_EntryLists[nColumn]->mnHeaderPos;
533     if (nPos == INVALID_HEADER_POS)
534         return;
535 
536     weld::ComboBox* pValList = maValueEdArr[nList-1];
537     int nListPos = nPos + 2;                 // for "empty" and "non-empty"
538 
539     const ScTypedStrData& rHdrEntry = m_EntryLists[nColumn]->maFilterEntries.maStrData[nPos];
540 
541     const OUString& aHdrStr = rHdrEntry.GetString();
542     bool bWasThere = nListPos < pValList->get_count() && aHdrStr == pValList->get_text(nListPos);
543     bool bInclude = !m_xBtnHeader->get_active();
544 
545     if (bInclude)           // Include entry
546     {
547         if (!bWasThere)
548             pValList->insert_text(nListPos, aHdrStr);
549     }
550     else                    // Omit entry
551     {
552         if (bWasThere)
553             pValList->remove(nListPos);
554     }
555 }
556 
ClearValueList(size_t nList)557 void ScFilterDlg::ClearValueList( size_t nList )
558 {
559     if (nList > 0 && nList <= QUERY_ENTRY_COUNT)
560     {
561         weld::ComboBox* pValList = maValueEdArr[nList-1];
562         pValList->clear();
563         pValList->append_text( aStrNotEmpty );
564         pValList->append_text( aStrEmpty );
565         pValList->set_entry_text( EMPTY_OUSTRING );
566     }
567 }
568 
GetFieldSelPos(SCCOL nField)569 size_t ScFilterDlg::GetFieldSelPos( SCCOL nField )
570 {
571     if ( nField >= theQueryData.nCol1 && nField <= theQueryData.nCol2 )
572         return static_cast<size_t>(nField - theQueryData.nCol1 + 1);
573     else
574         return 0;
575 }
576 
GetOutputItem()577 ScQueryItem* ScFilterDlg::GetOutputItem()
578 {
579     ScAddress       theCopyPos;
580     ScQueryParam    theParam( theQueryData );
581     bool            bCopyPosOk = false;
582 
583     if ( m_xBtnCopyResult->get_active() )
584     {
585         ScRefFlags nResult = theCopyPos.Parse(
586             m_xEdCopyArea->GetText(), *pDoc, pDoc->GetAddressConvention());
587         bCopyPosOk = (nResult & ScRefFlags::VALID) == ScRefFlags::VALID;
588     }
589 
590     if ( m_xBtnCopyResult->get_active() && bCopyPosOk )
591     {
592         theParam.bInplace   = false;
593         theParam.nDestTab   = theCopyPos.Tab();
594         theParam.nDestCol   = theCopyPos.Col();
595         theParam.nDestRow   = theCopyPos.Row();
596     }
597     else
598     {
599         theParam.bInplace   = true;
600         theParam.nDestTab   = 0;
601         theParam.nDestCol   = 0;
602         theParam.nDestRow   = 0;
603     }
604 
605     theParam.bHasHeader     = m_xBtnHeader->get_active();
606     theParam.bByRow         = true;
607     theParam.bDuplicate     = !m_xBtnUnique->get_active();
608     theParam.bCaseSens      = m_xBtnCase->get_active();
609     theParam.eSearchType    = m_xBtnRegExp->get_active() ? utl::SearchParam::SearchType::Regexp : utl::SearchParam::SearchType::Normal;
610     theParam.bDestPers      = m_xBtnDestPers->get_active();
611 
612     // only set the three - reset everything else
613 
614     pOutItem.reset( new ScQueryItem( nWhichQuery, &theParam ) );
615 
616     return pOutItem.get();
617 }
618 
IsRefInputMode() const619 bool ScFilterDlg::IsRefInputMode() const
620 {
621     return bRefInputMode;
622 }
623 
624 // Handler:
625 
IMPL_LINK(ScFilterDlg,BtnClearHdl,weld::Button &,rBtn,void)626 IMPL_LINK( ScFilterDlg, BtnClearHdl, weld::Button&, rBtn, void )
627 {
628     if ( &rBtn != m_xBtnClear.get() )
629         return;
630 
631     // scroll to the top
632     m_xScrollBar->vadjustment_set_value(0);
633     size_t nOffset = 0;
634     RefreshEditRow( nOffset);
635 
636     // clear all conditions
637     m_xLbConnect1->set_active(-1);
638     m_xLbConnect2->set_active(-1);
639     m_xLbConnect3->set_active(-1);
640     m_xLbConnect4->set_active(-1);
641     m_xLbField1->set_active(0);
642     m_xLbField2->set_active(0);
643     m_xLbField3->set_active(0);
644     m_xLbField4->set_active(0);
645     m_xLbCond1->set_active(0);
646     m_xLbCond2->set_active(0);
647     m_xLbCond3->set_active(0);
648     m_xLbCond4->set_active(0);
649     ClearValueList( 1 );
650     ClearValueList( 2 );
651     ClearValueList( 3 );
652     ClearValueList( 4 );
653 
654     // disable fields for second row onward
655     m_xLbConnect2->set_sensitive(false);
656     m_xLbConnect3->set_sensitive(false);
657     m_xLbConnect4->set_sensitive(false);
658     m_xLbField2->set_sensitive(false);
659     m_xLbField3->set_sensitive(false);
660     m_xLbField4->set_sensitive(false);
661     m_xLbCond2->set_sensitive(false);
662     m_xLbCond3->set_sensitive(false);
663     m_xLbCond4->set_sensitive(false);
664     m_xEdVal2->set_sensitive(false);
665     m_xEdVal3->set_sensitive(false);
666     m_xEdVal4->set_sensitive(false);
667     m_xBtnRemove2->set_sensitive(false);
668     m_xBtnRemove3->set_sensitive(false);
669     m_xBtnRemove4->set_sensitive(false);
670 
671     // clear query data objects
672     SCSIZE nCount = theQueryData.GetEntryCount();
673     if (maRefreshExceptQuery.size() < nCount + 1)
674         maRefreshExceptQuery.resize(nCount + 1, false);
675     for (SCSIZE i = 0; i < nCount; ++i)
676     {
677         theQueryData.GetEntry(i).bDoQuery = false;
678         maRefreshExceptQuery[i] = false;
679         theQueryData.GetEntry(i).nField = static_cast<SCCOL>(0);
680     }
681     maRefreshExceptQuery[0] = true;
682 }
683 
IMPL_LINK(ScFilterDlg,EndDlgHdl,weld::Button &,rBtn,void)684 IMPL_LINK( ScFilterDlg, EndDlgHdl, weld::Button&, rBtn, void )
685 {
686     if ( &rBtn == m_xBtnOk.get() )
687     {
688         bool bAreaInputOk = true;
689 
690         if ( m_xBtnCopyResult->get_active() )
691         {
692             if ( !pOptionsMgr->VerifyPosStr( m_xEdCopyArea->GetText() ) )
693             {
694                 if (!m_xExpander->get_expanded())
695                   m_xExpander->set_expanded(true);
696 
697                 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
698                                                           VclMessageType::Warning, VclButtonsType::Ok,
699                                                           ScResId(STR_INVALID_TABREF)));
700                 xBox->run();
701                 m_xEdCopyArea->GrabFocus();
702                 bAreaInputOk = false;
703             }
704         }
705 
706         if ( bAreaInputOk )
707         {
708             SetDispatcherLock( false );
709             SwitchToDocument();
710             GetBindings().GetDispatcher()->ExecuteList(FID_FILTER_OK,
711                                       SfxCallMode::SLOT | SfxCallMode::RECORD,
712                                       { GetOutputItem() });
713             response(RET_OK);
714         }
715     }
716     else if ( &rBtn == m_xBtnCancel.get() )
717     {
718         response(RET_CANCEL);
719     }
720 }
721 
IMPL_LINK_NOARG(ScFilterDlg,MoreExpandedHdl,weld::Expander &,void)722 IMPL_LINK_NOARG(ScFilterDlg, MoreExpandedHdl, weld::Expander&, void)
723 {
724     if ( m_xExpander->get_expanded() )
725         pTimer->Start();
726     else
727     {
728         pTimer->Stop();
729         bRefInputMode = false;
730         //@BugID 54702 Enable/disable only in Basic class
731         //SFX_APPWINDOW->Disable(FALSE);        //! general method in ScAnyRefDlg
732     }
733 }
734 
IMPL_LINK(ScFilterDlg,TimeOutHdl,Timer *,_pTimer,void)735 IMPL_LINK( ScFilterDlg, TimeOutHdl, Timer*, _pTimer, void )
736 {
737     // Check if RefInputMode is still true every 50ms
738     if (_pTimer == pTimer.get() && m_xDialog->has_toplevel_focus())
739         bRefInputMode = (m_xEdCopyArea->GetWidget()->has_focus() || m_xRbCopyArea->GetWidget()->has_focus());
740 
741     if ( m_xExpander->get_expanded() )
742         pTimer->Start();
743 }
744 
IMPL_LINK(ScFilterDlg,LbSelectHdl,weld::ComboBox &,rLb,void)745 IMPL_LINK(ScFilterDlg, LbSelectHdl, weld::ComboBox&, rLb, void)
746 {
747     /*
748      * Handle enable/disable logic depending on which ListBox was selected
749      */
750     sal_uInt16 nOffset = GetSliderPos();
751 
752     if ( &rLb == m_xLbConnect1.get() )
753     {
754         m_xLbField1->set_sensitive(true);
755         m_xLbCond1->set_sensitive(true);
756         m_xEdVal1->set_sensitive(true);
757         m_xBtnRemove1->set_sensitive(true);
758 
759         const sal_Int32 nConnect1 = m_xLbConnect1->get_active();
760         size_t nQE = nOffset;
761         theQueryData.GetEntry(nQE).eConnect =static_cast<ScQueryConnect>(nConnect1);
762         if (maRefreshExceptQuery.size() < nQE + 1)
763             maRefreshExceptQuery.resize(nQE + 1, false);
764         maRefreshExceptQuery[nQE] = true;
765     }
766     else if ( &rLb == m_xLbConnect2.get() )
767     {
768         m_xLbField2->set_sensitive(true);
769         m_xLbCond2->set_sensitive(true);
770         m_xEdVal2->set_sensitive(true);
771         m_xBtnRemove2->set_sensitive(true);
772 
773         const sal_Int32 nConnect2 = m_xLbConnect2->get_active();
774         size_t nQE = 1+nOffset;
775         theQueryData.GetEntry(nQE).eConnect =static_cast<ScQueryConnect>(nConnect2);
776         if (maRefreshExceptQuery.size() < nQE + 1)
777             maRefreshExceptQuery.resize(nQE + 1, false);
778         maRefreshExceptQuery[nQE]=true;
779     }
780     else if ( &rLb == m_xLbConnect3.get() )
781     {
782         m_xLbField3->set_sensitive(true);
783         m_xLbCond3->set_sensitive(true);
784         m_xEdVal3->set_sensitive(true);
785         m_xBtnRemove3->set_sensitive(true);
786 
787         const sal_Int32 nConnect3 = m_xLbConnect3->get_active();
788         size_t nQE = 2 + nOffset;
789         theQueryData.GetEntry(nQE).eConnect = static_cast<ScQueryConnect>(nConnect3);
790         if (maRefreshExceptQuery.size() < nQE + 1)
791             maRefreshExceptQuery.resize(nQE + 1, false);
792         maRefreshExceptQuery[nQE] = true;
793 
794     }
795     else if ( &rLb == m_xLbConnect4.get() )
796     {
797         m_xLbField4->set_sensitive(true);
798         m_xLbCond4->set_sensitive(true);
799         m_xEdVal4->set_sensitive(true);
800         m_xBtnRemove4->set_sensitive(true);
801 
802         const sal_Int32 nConnect4 = m_xLbConnect4->get_active();
803         size_t nQE = 3 + nOffset;
804         theQueryData.GetEntry(nQE).eConnect = static_cast<ScQueryConnect>(nConnect4);
805         if (maRefreshExceptQuery.size() < nQE + 1)
806             maRefreshExceptQuery.resize(nQE + 1, false);
807         maRefreshExceptQuery[nQE] = true;
808     }
809     else if ( &rLb == m_xLbField1.get() )
810     {
811         if ( m_xLbField1->get_active() == 0 )
812         {
813             m_xLbConnect2->set_active(-1);
814             m_xLbConnect3->set_active(-1);
815             m_xLbConnect4->set_active(-1);
816             m_xLbField2->set_active( 0 );
817             m_xLbField3->set_active( 0 );
818             m_xLbField4->set_active( 0 );
819             m_xLbCond2->set_active( 0 );
820             m_xLbCond3->set_active( 0 );
821             m_xLbCond4->set_active( 0 );
822             ClearValueList( 1 );
823             ClearValueList( 2 );
824             ClearValueList( 3 );
825             ClearValueList( 4 );
826 
827             m_xLbConnect2->set_sensitive(false);
828             m_xLbConnect3->set_sensitive(false);
829             m_xLbConnect4->set_sensitive(false);
830             m_xLbField2->set_sensitive(false);
831             m_xLbField3->set_sensitive(false);
832             m_xLbField4->set_sensitive(false);
833             m_xLbCond2->set_sensitive(false);
834             m_xLbCond3->set_sensitive(false);
835             m_xLbCond4->set_sensitive(false);
836             m_xEdVal2->set_sensitive(false);
837             m_xEdVal3->set_sensitive(false);
838             m_xEdVal4->set_sensitive(false);
839             m_xBtnRemove2->set_sensitive(false);
840             m_xBtnRemove3->set_sensitive(false);
841             m_xBtnRemove4->set_sensitive(false);
842             SCSIZE nCount = theQueryData.GetEntryCount();
843             if (maRefreshExceptQuery.size() < nCount + 1)
844                 maRefreshExceptQuery.resize(nCount + 1, false);
845             for (SCSIZE i = nOffset; i < nCount; ++i)
846             {
847                 theQueryData.GetEntry(i).bDoQuery = false;
848                 maRefreshExceptQuery[i] = false;
849                 theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
850             }
851             maRefreshExceptQuery[nOffset] = true;
852         }
853         else
854         {
855             UpdateValueList( 1 );
856             if ( !m_xLbConnect2->get_sensitive() )
857             {
858                 m_xLbConnect2->set_sensitive(true);
859             }
860             theQueryData.GetEntry(nOffset).bDoQuery = true;
861             const sal_Int32 nField  = rLb.get_active();
862             theQueryData.GetEntry(nOffset).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
863         }
864     }
865     else if ( &rLb == m_xLbField2.get() )
866     {
867         if ( m_xLbField2->get_active() == 0 )
868         {
869             m_xLbConnect3->set_active(-1);
870             m_xLbConnect4->set_active(-1);
871             m_xLbField3->set_active( 0 );
872             m_xLbField4->set_active( 0 );
873             m_xLbCond3->set_active( 0 );
874             m_xLbCond4->set_active( 0 );
875             ClearValueList( 2 );
876             ClearValueList( 3 );
877             ClearValueList( 4 );
878 
879             m_xLbConnect3->set_sensitive(false);
880             m_xLbConnect4->set_sensitive(false);
881             m_xLbField3->set_sensitive(false);
882             m_xLbField4->set_sensitive(false);
883             m_xLbCond3->set_sensitive(false);
884             m_xLbCond4->set_sensitive(false);
885             m_xEdVal3->set_sensitive(false);
886             m_xEdVal4->set_sensitive(false);
887             m_xBtnRemove3->set_sensitive(false);
888             m_xBtnRemove4->set_sensitive(false);
889 
890             sal_uInt16 nTemp=nOffset+1;
891             SCSIZE nCount = theQueryData.GetEntryCount();
892             if (maRefreshExceptQuery.size() < nCount)
893                 maRefreshExceptQuery.resize(nCount, false);
894             for (SCSIZE i= nTemp; i< nCount; i++)
895             {
896                 theQueryData.GetEntry(i).bDoQuery = false;
897                 maRefreshExceptQuery[i] = false;
898                 theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
899             }
900             maRefreshExceptQuery[nTemp] = true;
901         }
902         else
903         {
904             UpdateValueList( 2 );
905             if ( !m_xLbConnect3->get_sensitive() )
906             {
907                 m_xLbConnect3->set_sensitive(true);
908             }
909             const sal_Int32 nField = rLb.get_active();
910             sal_uInt16 nQ=1+nOffset;
911             theQueryData.GetEntry(nQ).bDoQuery = true;
912             theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
913         }
914     }
915     else if ( &rLb == m_xLbField3.get() )
916     {
917         if ( m_xLbField3->get_active() == 0 )
918         {
919             m_xLbConnect4->set_active(-1);
920             m_xLbField4->set_active( 0 );
921             m_xLbCond4->set_active( 0 );
922             ClearValueList( 3 );
923             ClearValueList( 4 );
924 
925             m_xLbConnect4->set_sensitive(false);
926             m_xLbField4->set_sensitive(false);
927             m_xLbCond4->set_sensitive(false);
928             m_xEdVal4->set_sensitive(false);
929             m_xBtnRemove4->set_sensitive(false);
930 
931             sal_uInt16 nTemp=nOffset+2;
932             SCSIZE nCount = theQueryData.GetEntryCount();
933             if (maRefreshExceptQuery.size() < nCount)
934                 maRefreshExceptQuery.resize(nCount, false);
935             for (SCSIZE i = nTemp; i < nCount; ++i)
936             {
937                 theQueryData.GetEntry(i).bDoQuery = false;
938                 maRefreshExceptQuery[i] = false;
939                 theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
940             }
941             maRefreshExceptQuery[nTemp] = true;
942         }
943         else
944         {
945             UpdateValueList( 3 );
946             if ( !m_xLbConnect4->get_sensitive() )
947             {
948                 m_xLbConnect4->set_sensitive(true);
949             }
950 
951             const sal_Int32 nField = rLb.get_active();
952             sal_uInt16 nQ=2+nOffset;
953             theQueryData.GetEntry(nQ).bDoQuery = true;
954             theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
955 
956         }
957     }
958     else if ( &rLb == m_xLbField4.get() )
959     {
960         if ( m_xLbField4->get_active() == 0 )
961         {
962             ClearValueList( 4 );
963             sal_uInt16 nTemp=nOffset+3;
964             SCSIZE nCount = theQueryData.GetEntryCount();
965             if (maRefreshExceptQuery.size() < nCount)
966                 maRefreshExceptQuery.resize(nCount, false);
967             for (SCSIZE i = nTemp; i < nCount; ++i)
968             {
969                 theQueryData.GetEntry(i).bDoQuery = false;
970                 maRefreshExceptQuery[i] = false;
971                 theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
972             }
973             maRefreshExceptQuery[nTemp] = true;
974         }
975         else
976         {
977             UpdateValueList( 4 );
978             const sal_Int32 nField = rLb.get_active();
979             sal_uInt16 nQ=3+nOffset;
980             theQueryData.GetEntry(nQ).bDoQuery = true;
981             theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
982         }
983 
984     }
985     else if ( &rLb == m_xLbCond1.get())
986     {
987         theQueryData.GetEntry(nOffset).eOp=static_cast<ScQueryOp>(rLb.get_active());
988     }
989     else if ( &rLb == m_xLbCond2.get())
990     {
991         sal_uInt16 nQ=1+nOffset;
992         theQueryData.GetEntry(nQ).eOp=static_cast<ScQueryOp>(rLb.get_active());
993     }
994     else if ( &rLb == m_xLbCond3.get())
995     {
996         sal_uInt16 nQ=2+nOffset;
997         theQueryData.GetEntry(nQ).eOp=static_cast<ScQueryOp>(rLb.get_active());
998     }
999     else
1000     {
1001         sal_uInt16 nQ=3+nOffset;
1002         theQueryData.GetEntry(nQ).eOp=static_cast<ScQueryOp>(rLb.get_active());
1003     }
1004 }
1005 
IMPL_LINK(ScFilterDlg,CheckBoxHdl,weld::Toggleable &,rBox,void)1006 IMPL_LINK( ScFilterDlg, CheckBoxHdl, weld::Toggleable&, rBox, void )
1007 {
1008     //  Column headers:
1009     //      Field list: Columnxx <-> column header string
1010     //      Value list: Column header value not applicable.
1011     //  Upper/lower case:
1012     //      Value list: completely new
1013 
1014     if ( &rBox == m_xBtnHeader.get() )              // Field list and value list
1015     {
1016         const sal_Int32 nCurSel1 = m_xLbField1->get_active();
1017         const sal_Int32 nCurSel2 = m_xLbField2->get_active();
1018         const sal_Int32 nCurSel3 = m_xLbField3->get_active();
1019         const sal_Int32 nCurSel4 = m_xLbField4->get_active();
1020         FillFieldLists();
1021         m_xLbField1->set_active( nCurSel1 );
1022         m_xLbField2->set_active( nCurSel2 );
1023         m_xLbField3->set_active( nCurSel3 );
1024         m_xLbField4->set_active( nCurSel4 );
1025 
1026         UpdateHdrInValueList( 1 );
1027         UpdateHdrInValueList( 2 );
1028         UpdateHdrInValueList( 3 );
1029         UpdateHdrInValueList( 4 );
1030     }
1031 
1032     if ( &rBox == m_xBtnCase.get() )            // Complete value list
1033     {
1034         m_EntryLists.clear();
1035         UpdateValueList( 1 );       // current text is recorded
1036         UpdateValueList( 2 );
1037         UpdateValueList( 3 );
1038         UpdateValueList( 4 );
1039     }
1040 }
1041 
IMPL_LINK(ScFilterDlg,ValModifyHdl,weld::ComboBox &,rEd,void)1042 IMPL_LINK( ScFilterDlg, ValModifyHdl, weld::ComboBox&, rEd, void )
1043 {
1044     size_t nOffset = GetSliderPos();
1045     size_t i = 0;
1046     size_t nQE = i + nOffset;
1047     OUString aStrVal = rEd.get_active_text();
1048     weld::ComboBox*  pLbCond   = m_xLbCond1.get();
1049     weld::ComboBox*  pLbField  = m_xLbField1.get();
1050     if ( &rEd == m_xEdVal2.get() )
1051     {
1052         pLbCond  = m_xLbCond2.get();
1053         pLbField = m_xLbField2.get();
1054         i=1;
1055         nQE=i+nOffset;
1056     }
1057     if ( &rEd == m_xEdVal3.get() )
1058     {
1059         pLbCond = m_xLbCond3.get();
1060         pLbField = m_xLbField3.get();
1061         i=2;
1062         nQE=i+nOffset;
1063     }
1064     if ( &rEd == m_xEdVal4.get() )
1065     {
1066         pLbCond = m_xLbCond4.get();
1067         pLbField = m_xLbField4.get();
1068         i=3;
1069         nQE=i+nOffset;
1070     }
1071 
1072     if ( aStrEmpty == aStrVal || aStrNotEmpty == aStrVal )
1073     {
1074         pLbCond->set_active_text(OUString('='));
1075         pLbCond->set_sensitive(false);
1076     }
1077     else
1078         pLbCond->set_sensitive(true);
1079 
1080     if (maHasDates.size() < nQE + 1)
1081         maHasDates.resize(nQE + 1, false);
1082     if (maRefreshExceptQuery.size() < nQE + 1)
1083         maRefreshExceptQuery.resize(nQE + 1, false);
1084 
1085     ScQueryEntry& rEntry = theQueryData.GetEntry( nQE );
1086     ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1087     bool bDoThis = (pLbField->get_active() != 0);
1088     rEntry.bDoQuery = bDoThis;
1089 
1090     if ( !(rEntry.bDoQuery || maRefreshExceptQuery[nQE]) )
1091         return;
1092 
1093     bool bByEmptyOrNotByEmpty = false;
1094     if ( aStrEmpty == aStrVal )
1095     {
1096         bByEmptyOrNotByEmpty = true;
1097         rEntry.SetQueryByEmpty();
1098     }
1099     else if ( aStrNotEmpty == aStrVal )
1100     {
1101         bByEmptyOrNotByEmpty = true;
1102         rEntry.SetQueryByNonEmpty();
1103     }
1104     else
1105     {
1106         rItem.maString = pDoc->GetSharedStringPool().intern(aStrVal);
1107         rItem.mfVal = 0.0;
1108         rItem.meType = ScQueryEntry::ByString;
1109     }
1110 
1111     const sal_Int32 nField = pLbField->get_active();
1112     rEntry.nField = nField ? (theQueryData.nCol1 +
1113         static_cast<SCCOL>(nField) - 1) : static_cast<SCCOL>(0);
1114 
1115     ScQueryOp eOp  = static_cast<ScQueryOp>(pLbCond->get_active());
1116     rEntry.eOp     = eOp;
1117     if (maHasDates[nQE] && !bByEmptyOrNotByEmpty)
1118         rItem.meType = ScQueryEntry::ByDate;
1119 }
1120 
IMPL_LINK(ScFilterDlg,BtnRemoveHdl,weld::Button &,rBtn,void)1121 IMPL_LINK( ScFilterDlg, BtnRemoveHdl, weld::Button&, rBtn, void )
1122 {
1123     // Calculate the row to delete
1124     sal_uInt16 nOffset = GetSliderPos();
1125     int nButtonIndex = 0;
1126     if ( &rBtn == m_xBtnRemove2.get() )
1127         nButtonIndex = 1;
1128     if ( &rBtn == m_xBtnRemove3.get() )
1129         nButtonIndex = 2;
1130     if ( &rBtn == m_xBtnRemove4.get() )
1131         nButtonIndex = 3;
1132     SCSIZE nRowToDelete = nOffset + nButtonIndex;
1133 
1134     // Check that the index is sensible
1135     SCSIZE nCount = theQueryData.GetEntryCount();
1136     if (nRowToDelete >= nCount)
1137     {
1138         SAL_WARN( "sc", "ScFilterDlg::BtnRemoveHdl: could not delete row - invalid index.");
1139         return;
1140     }
1141 
1142     // Resize maRefreshExceptQuery
1143     if (maRefreshExceptQuery.size() < nCount + 1)
1144         maRefreshExceptQuery.resize(nCount + 1, false);
1145 
1146     // Move all the subsequent rows back one position;
1147     // also find the last row, which we will delete
1148     SCSIZE nRowToClear = nCount-1;
1149     for (SCSIZE i = nRowToDelete; i < nCount-1; ++i)
1150     {
1151         if (theQueryData.GetEntry(i+1).bDoQuery)
1152         {
1153             theQueryData.GetEntry(i) = theQueryData.GetEntry(i+1);
1154         }
1155         else
1156         {
1157             nRowToClear = i;
1158             break;
1159         }
1160     }
1161 
1162     // If the next row is being edited, but not confirmed, move it back
1163     // one position
1164     if (nRowToClear < nCount-1  &&  maRefreshExceptQuery[nRowToClear+1])
1165     {
1166         theQueryData.GetEntry(nRowToClear) = theQueryData.GetEntry(nRowToClear+1);
1167         maRefreshExceptQuery[nRowToClear] = true;
1168         maRefreshExceptQuery[nRowToClear+1] = false;
1169     }
1170     else
1171     {
1172         // Remove the very last one, since everything has moved back
1173         theQueryData.GetEntry(nRowToClear).bDoQuery = false;
1174         theQueryData.GetEntry(nRowToClear).nField =  static_cast<SCCOL>(0);
1175         maRefreshExceptQuery[nRowToClear] = false;
1176     }
1177 
1178     // Always enable the very first row
1179     if (!theQueryData.GetEntry(0).bDoQuery)
1180     {
1181         maRefreshExceptQuery[0] = true;
1182     }
1183 
1184     // Refresh the UI
1185     RefreshEditRow( nOffset );
1186 
1187     // Special handling if the very first row was cleared
1188     if (!theQueryData.GetEntry(0).bDoQuery)
1189     {
1190         m_xLbConnect1->set_active(-1);
1191         m_xLbField1->set_active(0);
1192         m_xLbField1->set_sensitive(true);
1193         m_xLbCond1->set_active(0);
1194         m_xLbCond1->set_sensitive(true);
1195         ClearValueList(1);
1196     }
1197 }
1198 
IMPL_LINK_NOARG(ScFilterDlg,ScrollHdl,weld::ScrolledWindow &,void)1199 IMPL_LINK_NOARG(ScFilterDlg, ScrollHdl, weld::ScrolledWindow&, void)
1200 {
1201     SliderMoved();
1202 }
1203 
SliderMoved()1204 void ScFilterDlg::SliderMoved()
1205 {
1206     size_t nOffset = GetSliderPos();
1207     RefreshEditRow( nOffset);
1208 }
1209 
GetSliderPos() const1210 size_t ScFilterDlg::GetSliderPos() const
1211 {
1212     return static_cast<size_t>(m_xScrollBar->vadjustment_get_value());
1213 }
1214 
RefreshEditRow(size_t nOffset)1215 void ScFilterDlg::RefreshEditRow( size_t nOffset )
1216 {
1217     if (nOffset==0)
1218         maConnLbArr[0]->hide();
1219     else
1220         maConnLbArr[0]->show();
1221 
1222     for (size_t i = 0; i < QUERY_ENTRY_COUNT; ++i)
1223     {
1224         OUString aValStr;
1225         size_t nCondPos = 0;
1226         size_t nFieldSelPos = 0;
1227         size_t nQE = i + nOffset;
1228 
1229         if (maRefreshExceptQuery.size() < nQE + 1)
1230             maRefreshExceptQuery.resize(nQE + 1, false);
1231 
1232         ScQueryEntry& rEntry = theQueryData.GetEntry( nQE);
1233         if ( rEntry.bDoQuery || maRefreshExceptQuery[nQE] )
1234         {
1235             nCondPos = static_cast<size_t>(rEntry.eOp);
1236             if(rEntry.bDoQuery)
1237                nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );
1238 
1239             const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1240             OUString aQueryStr = rItem.maString.getString();
1241             if (rEntry.IsQueryByEmpty())
1242             {
1243                 aValStr = aStrEmpty;
1244                 maCondLbArr[i]->set_sensitive(false);
1245             }
1246             else if (rEntry.IsQueryByNonEmpty())
1247             {
1248                 aValStr = aStrNotEmpty;
1249                 maCondLbArr[i]->set_sensitive(false);
1250             }
1251             else if (rEntry.IsQueryByTextColor() || rEntry.IsQueryByBackgroundColor())
1252             {
1253                 continue;
1254             }
1255             else
1256             {
1257                 SetValString(aQueryStr, rItem, aValStr);
1258                 maCondLbArr[i]->set_sensitive(true);
1259             }
1260             maFieldLbArr[i]->set_sensitive(true);
1261             maValueEdArr[i]->set_sensitive(true);
1262             maRemoveBtnArr[i]->set_sensitive(true);
1263 
1264             if (nOffset==0)
1265             {
1266                 if (i<3)
1267                 {
1268                     if(rEntry.bDoQuery)
1269                         maConnLbArr[i+1]->set_sensitive(true);
1270                     else
1271                         maConnLbArr[i+1]->set_sensitive(false);
1272                     size_t nQENext = nQE + 1;
1273                     if (maRefreshExceptQuery.size() < nQENext + 1)
1274                         maRefreshExceptQuery.resize(nQENext + 1, false);
1275                     if (theQueryData.GetEntry(nQENext).bDoQuery || maRefreshExceptQuery[nQENext])
1276                         maConnLbArr[i+1]->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(nQENext).eConnect) );
1277                     else
1278                         maConnLbArr[i+1]->set_active(-1);
1279                 }
1280             }
1281             else
1282             {
1283                 if(theQueryData.GetEntry( nQE-1).bDoQuery)
1284                     maConnLbArr[i]->set_sensitive(true);
1285                 else
1286                     maConnLbArr[i]->set_sensitive(false);
1287 
1288                 if (maRefreshExceptQuery.size() < nQE + 1)
1289                     maRefreshExceptQuery.resize(nQE + 1, false);
1290                 if(rEntry.bDoQuery || maRefreshExceptQuery[nQE])
1291                     maConnLbArr[i]->set_active( static_cast<sal_uInt16>(rEntry.eConnect) );
1292                 else
1293                     maConnLbArr[i]->set_active(-1);
1294             }
1295 
1296         }
1297         else
1298         {
1299             if (nOffset==0)
1300             {
1301                 if(i<3)
1302                 {
1303                     maConnLbArr[i+1]->set_active(-1);
1304                     maConnLbArr[i+1]->set_sensitive(false);
1305                 }
1306             }
1307             else
1308             {
1309                 if(theQueryData.GetEntry( nQE-1).bDoQuery)
1310                     maConnLbArr[i]->set_sensitive(true);
1311                 else
1312                     maConnLbArr[i]->set_sensitive(false);
1313                 maConnLbArr[i]->set_active(-1);
1314             }
1315             maFieldLbArr[i]->set_sensitive(false);
1316             maCondLbArr[i]->set_sensitive(false);
1317             maValueEdArr[i]->set_sensitive(false);
1318             maRemoveBtnArr[i]->set_sensitive(false);
1319         }
1320         maFieldLbArr[i]->set_active( nFieldSelPos );
1321         maCondLbArr [i]->set_active( nCondPos );
1322         maValueEdArr[i]->set_entry_text( aValStr );
1323         UpdateValueList(i+1);
1324     }
1325 }
1326 
SetValString(const OUString & rQueryStr,const ScQueryEntry::Item & rItem,OUString & rValStr)1327 void ScFilterDlg::SetValString( const OUString& rQueryStr, const ScQueryEntry::Item& rItem,
1328     OUString& rValStr )
1329 {
1330     if (rQueryStr.isEmpty())
1331     {
1332         pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
1333         if (rItem.meType == ScQueryEntry::ByValue)
1334         {
1335             if (pDoc)
1336             {
1337                 pDoc->GetFormatTable()->GetInputLineString(rItem.mfVal, 0, rValStr);
1338             }
1339         }
1340         else if (rItem.meType == ScQueryEntry::ByDate)
1341         {
1342             if (pDoc)
1343             {
1344                 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
1345                 pFormatter->GetInputLineString(rItem.mfVal,
1346                                                pFormatter->GetStandardFormat( SvNumFormatType::DATE), rValStr);
1347             }
1348         }
1349         else
1350         {
1351             SAL_WARN( "sc", "ScFilterDlg::SetValString: empty query string, really?");
1352             rValStr = rQueryStr;
1353         }
1354     }
1355     else
1356     {
1357         // XXX NOTE: if not ByString we just assume this has been
1358         // set to a proper string corresponding to the numeric
1359         // value earlier!
1360         rValStr = rQueryStr;
1361     }
1362 }
1363 
1364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1365