lok: Don't attempt to select the exact text after a failed search.
[LibreOffice.git] / cui / source / dialogs / cuifmsearch.cxx
blob2a5c31f5c199f5b3d8f61f0795e3e05e51f8837a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/debug.hxx>
21 #include <vcl/layout.hxx>
22 #include <vcl/svapp.hxx>
23 #include <dialmgr.hxx>
24 #include <sfx2/tabdlg.hxx>
25 #include <osl/mutex.hxx>
26 #include <sfx2/app.hxx>
27 #include <cuires.hrc>
28 #include <svx/fmsrccfg.hxx>
29 #include <svx/fmsrcimp.hxx>
30 #include "fmsearch.hrc"
31 #include "cuifmsearch.hxx"
32 #include <svx/srchdlg.hxx>
33 #include <svl/cjkoptions.hxx>
34 #include <com/sun/star/i18n/TransliterationModules.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/string.hxx>
37 #include <svx/svxdlg.hxx>
38 #include <sal/macros.h>
39 #include <boost/scoped_ptr.hpp>
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::i18n;
43 using namespace ::svxform;
44 using namespace ::com::sun::star::sdbc;
45 using namespace ::com::sun::star::util;
47 #define MAX_HISTORY_ENTRIES 50
49 void FmSearchDialog::initCommon( const Reference< XResultSet >& _rxCursor )
51 // init the engine
52 DBG_ASSERT( m_pSearchEngine, "FmSearchDialog::initCommon: have no engine!" );
53 m_pSearchEngine->SetProgressHandler(LINK(this, FmSearchDialog, OnSearchProgress));
55 // some layout changes according to available CJK options
56 SvtCJKOptions aCJKOptions;
57 if (!aCJKOptions.IsJapaneseFindEnabled())
59 // hide the options for the japanese search
60 m_pSoundsLikeCJK->Hide();
61 m_pSoundsLikeCJKSettings->Hide();
64 if (!aCJKOptions.IsCJKFontEnabled())
66 m_pHalfFullFormsCJK->Hide();
68 // never ignore the width (ignoring is expensive) if the option is not available at all
69 m_pSearchEngine->SetIgnoreWidthCJK( false );
72 // some initial record texts
73 m_pftRecord->SetText( OUString::number(_rxCursor->getRow()) );
74 m_pbClose->SetHelpText(OUString());
77 FmSearchDialog::FmSearchDialog(vcl::Window* pParent, const OUString& sInitialText, const ::std::vector< OUString >& _rContexts, sal_Int16 nInitialContext,
78 const Link<>& lnkContextSupplier)
79 :ModalDialog(pParent, "RecordSearchDialog", "cui/ui/fmsearchdialog.ui")
80 ,m_sCancel( Button::GetStandardText( StandardButtonType::Cancel ) )
81 ,m_pPreSearchFocus( NULL )
82 ,m_lnkContextSupplier(lnkContextSupplier)
83 ,m_pConfig( NULL )
85 get(m_prbSearchForText,"rbSearchForText");
86 get(m_prbSearchForNull,"rbSearchForNull");
87 get(m_prbSearchForNotNull,"rbSearchForNotNull");
88 get(m_pcmbSearchText,"cmbSearchText");
89 m_pcmbSearchText->set_width_request(m_pcmbSearchText->approximate_char_width() * 42);
90 get(m_plbForm,"lbForm");
91 m_plbForm->set_width_request(m_plbForm->approximate_char_width() * 42);
92 get(m_prbAllFields,"rbAllFields");
93 get(m_prbSingleField,"rbSingleField");
94 get(m_plbField,"lbField");
95 get(m_plbPosition,"lbPosition");
96 get(m_pcbUseFormat,"cbUseFormat");
97 get(m_pcbCase,"cbCase");
98 get(m_pcbBackwards,"cbBackwards");
99 get(m_pcbStartOver,"cbStartOver");
100 get(m_pcbWildCard,"cbWildCard");
101 get(m_pcbRegular,"cbRegular");
102 get(m_pcbApprox,"cbApprox");
103 get(m_ppbApproxSettings,"pbApproxSettings");
104 get(m_pHalfFullFormsCJK,"HalfFullFormsCJK");
105 get(m_pSoundsLikeCJK,"SoundsLikeCJK");
106 get(m_pSoundsLikeCJKSettings,"SoundsLikeCJKSettings");
107 get(m_pbSearchAgain,"pbSearchAgain");
108 m_sSearch = m_pbSearchAgain->GetText();
109 get(m_pftRecord,"ftRecord");
110 get(m_pftHint,"ftHint");
111 get(m_pftPosition,"ftPosition");
112 get(m_pftForm,"ftForm");
113 get(m_pbClose,"close");
115 DBG_ASSERT(m_lnkContextSupplier.IsSet(), "FmSearchDialog::FmSearchDialog : have no ContextSupplier !");
117 FmSearchContext fmscInitial;
118 fmscInitial.nContext = nInitialContext;
119 m_lnkContextSupplier.Call(&fmscInitial);
120 DBG_ASSERT(fmscInitial.xCursor.is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
121 DBG_ASSERT(comphelper::string::getTokenCount(fmscInitial.strUsedFields, ';') == (sal_Int32)fmscInitial.arrFields.size(),
122 "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplied !");
123 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
124 for (sal_Int32 i=0; i<(sal_Int32)fmscInitial.arrFields.size(); ++i)
125 DBG_ASSERT(fmscInitial.arrFields.at(i).is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
126 #endif // (OSL_DEBUG_LEVEL > 1) || DBG_UTIL
128 for ( ::std::vector< OUString >::const_iterator context = _rContexts.begin();
129 context != _rContexts.end();
130 ++context
133 m_arrContextFields.push_back(OUString());
134 m_plbForm->InsertEntry(*context);
136 m_plbForm->SelectEntryPos(nInitialContext);
138 m_plbForm->SetSelectHdl(LINK(this, FmSearchDialog, OnContextSelection));
140 if (m_arrContextFields.size() == 1)
142 // hide dispensable controls
143 m_pftForm->Hide();
144 m_plbForm->Hide();
147 m_pSearchEngine = new FmSearchEngine(
148 ::comphelper::getProcessComponentContext(), fmscInitial.xCursor, fmscInitial.strUsedFields, fmscInitial.arrFields, SM_ALLOWSCHEDULE );
149 initCommon( fmscInitial.xCursor );
151 if ( !fmscInitial.sFieldDisplayNames.isEmpty() )
152 { // use the display names if supplied
153 DBG_ASSERT(comphelper::string::getTokenCount(fmscInitial.sFieldDisplayNames, ';') == comphelper::string::getTokenCount(fmscInitial.strUsedFields, ';'),
154 "FmSearchDialog::FmSearchDialog : invalid initial context description !");
155 Init(fmscInitial.sFieldDisplayNames, sInitialText);
157 else
158 Init(fmscInitial.strUsedFields, sInitialText);
161 FmSearchDialog::~FmSearchDialog()
163 disposeOnce();
166 void FmSearchDialog::dispose()
168 if (m_aDelayedPaint.IsActive())
169 m_aDelayedPaint.Stop();
171 SaveParams();
173 delete m_pConfig;
174 m_pConfig = NULL;
176 delete m_pSearchEngine;
177 m_pSearchEngine = NULL;
179 m_prbSearchForText.clear();
180 m_prbSearchForNull.clear();
181 m_prbSearchForNotNull.clear();
182 m_pcmbSearchText.clear();
183 m_pftForm.clear();
184 m_plbForm.clear();
185 m_prbAllFields.clear();
186 m_prbSingleField.clear();
187 m_plbField.clear();
188 m_pftPosition.clear();
189 m_plbPosition.clear();
190 m_pcbUseFormat.clear();
191 m_pcbCase.clear();
192 m_pcbBackwards.clear();
193 m_pcbStartOver.clear();
194 m_pcbWildCard.clear();
195 m_pcbRegular.clear();
196 m_pcbApprox.clear();
197 m_ppbApproxSettings.clear();
198 m_pHalfFullFormsCJK.clear();
199 m_pSoundsLikeCJK.clear();
200 m_pSoundsLikeCJKSettings.clear();
201 m_pftRecord.clear();
202 m_pftHint.clear();
203 m_pbSearchAgain.clear();
204 m_pbClose.clear();
205 m_pPreSearchFocus.clear();
207 ModalDialog::dispose();
210 void FmSearchDialog::Init(const OUString& strVisibleFields, const OUString& sInitialText)
212 //the initialization of all the Controls
213 m_prbSearchForText->SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
214 m_prbSearchForNull->SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
215 m_prbSearchForNotNull->SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
217 m_prbAllFields->SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
218 m_prbSingleField->SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
220 m_pbSearchAgain->SetClickHdl(LINK(this, FmSearchDialog, OnClickedSearchAgain));
221 m_ppbApproxSettings->SetClickHdl(LINK(this, FmSearchDialog, OnClickedSpecialSettings));
222 m_pSoundsLikeCJKSettings->SetClickHdl(LINK(this, FmSearchDialog, OnClickedSpecialSettings));
224 m_plbPosition->SetSelectHdl(LINK(this, FmSearchDialog, OnPositionSelected));
225 m_plbField->SetSelectHdl(LINK(this, FmSearchDialog, OnFieldSelected));
227 m_pcmbSearchText->SetModifyHdl(LINK(this, FmSearchDialog, OnSearchTextModified));
228 m_pcmbSearchText->EnableAutocomplete(false);
229 m_pcmbSearchText->SetGetFocusHdl(LINK(this, FmSearchDialog, OnFocusGrabbed));
231 m_pcbUseFormat->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
232 m_pcbBackwards->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
233 m_pcbStartOver->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
234 m_pcbCase->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
235 m_pcbWildCard->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
236 m_pcbRegular->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
237 m_pcbApprox->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
238 m_pHalfFullFormsCJK->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
239 m_pSoundsLikeCJK->SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
241 // fill the listboxes
242 // method of field comparison
243 sal_uInt16 nResIds[] = {
244 RID_STR_SEARCH_ANYWHERE,
245 RID_STR_SEARCH_BEGINNING,
246 RID_STR_SEARCH_END,
247 RID_STR_SEARCH_WHOLE
249 for ( size_t i=0; i<SAL_N_ELEMENTS(nResIds); ++i )
250 m_plbPosition->InsertEntry( OUString( CUI_RES( nResIds[i] ) ) );
251 m_plbPosition->SelectEntryPos(MATCHING_ANYWHERE);
253 // the field listbox
254 for (sal_Int32 i=0; i < comphelper::string::getTokenCount(strVisibleFields, ';'); ++i)
255 m_plbField->InsertEntry(strVisibleFields.getToken(i, ';'));
258 m_pConfig = new FmSearchConfigItem;
259 LoadParams();
261 m_pcmbSearchText->SetText(sInitialText);
262 // if the Edit-line has changed the text (e.g. because it contains
263 // control characters, as can be the case with memo fields), I use
264 // an empty OUString.
265 OUString sRealSetText = m_pcmbSearchText->GetText();
266 if (!sRealSetText.equals(sInitialText))
267 m_pcmbSearchText->SetText(OUString());
268 LINK(this, FmSearchDialog, OnSearchTextModified).Call(m_pcmbSearchText);
270 // initial
271 m_aDelayedPaint.SetTimeoutHdl(LINK(this, FmSearchDialog, OnDelayedPaint));
272 m_aDelayedPaint.SetTimeout(500);
273 EnableSearchUI(true);
275 if ( m_prbSearchForText->IsChecked() )
276 m_pcmbSearchText->GrabFocus();
280 bool FmSearchDialog::Close()
282 // If the close button is disabled and ESC is pressed in a dialog,
283 // then Frame will call Close anyway, which I don't want to happen
284 // while I'm in the middle of a search (maybe one that's running
285 // in its own thread)
286 if (!m_pbClose->IsEnabled())
287 return false;
288 return ModalDialog::Close();
291 IMPL_LINK(FmSearchDialog, OnClickedFieldRadios, Button*, pButton)
293 if ((pButton == m_prbSearchForText) || (pButton == m_prbSearchForNull) || (pButton == m_prbSearchForNotNull))
295 EnableSearchForDependees(true);
297 else
298 // en- or disable field list box accordingly
299 if (pButton == m_prbSingleField)
301 m_plbField->Enable();
302 m_pSearchEngine->RebuildUsedFields(m_plbField->GetSelectEntryPos());
304 else
306 m_plbField->Disable();
307 m_pSearchEngine->RebuildUsedFields(-1);
310 return 0;
313 IMPL_LINK_NOARG(FmSearchDialog, OnClickedSearchAgain)
315 if (m_pbClose->IsEnabled())
316 { // the button has the function 'search'
317 OUString strThisRoundText = m_pcmbSearchText->GetText();
318 // to history
319 m_pcmbSearchText->RemoveEntry(strThisRoundText);
320 m_pcmbSearchText->InsertEntry(strThisRoundText, 0);
321 // the remove/insert makes sure that a) the OUString does not appear twice and
322 // that b) the last searched strings are at the beginning and limit the list length
323 while (m_pcmbSearchText->GetEntryCount() > MAX_HISTORY_ENTRIES)
324 m_pcmbSearchText->RemoveEntryAt(m_pcmbSearchText->GetEntryCount()-1);
326 // take out the 'overflow' hint
327 m_pftHint->SetText(OUString());
328 m_pftHint->Invalidate();
330 if (m_pcbStartOver->IsChecked())
332 m_pcbStartOver->Check(false);
333 EnableSearchUI(false);
334 if (m_prbSearchForText->IsChecked())
335 m_pSearchEngine->StartOver(strThisRoundText);
336 else
337 m_pSearchEngine->StartOverSpecial(m_prbSearchForNull->IsChecked());
339 else
341 EnableSearchUI(false);
342 if (m_prbSearchForText->IsChecked())
343 m_pSearchEngine->SearchNext(strThisRoundText);
344 else
345 m_pSearchEngine->SearchNextSpecial(m_prbSearchForNull->IsChecked());
348 else
349 { // the button has the function 'cancel'
350 DBG_ASSERT(m_pSearchEngine->GetSearchMode() != SM_BRUTE, "FmSearchDialog, OnClickedSearchAgain : falscher Modus !");
351 // the CancelButton is usually only disabled, when working in a thread or with reschedule
352 m_pSearchEngine->CancelSearch();
353 // the ProgressHandler is called when it's really finished, here it's only a demand
355 return 0;
358 IMPL_LINK(FmSearchDialog, OnClickedSpecialSettings, Button*, pButton )
360 if (m_ppbApproxSettings == pButton)
362 boost::scoped_ptr<AbstractSvxSearchSimilarityDialog> pDlg;
364 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
365 if ( pFact )
366 pDlg.reset(pFact->CreateSvxSearchSimilarityDialog( this, m_pSearchEngine->GetLevRelaxed(), m_pSearchEngine->GetLevOther(),
367 m_pSearchEngine->GetLevShorter(), m_pSearchEngine->GetLevLonger() ));
368 DBG_ASSERT( pDlg, "FmSearchDialog, OnClickedSpecialSettings: could not load the dialog!" );
370 if ( pDlg && pDlg->Execute() == RET_OK )
372 m_pSearchEngine->SetLevRelaxed( pDlg->IsRelaxed() );
373 m_pSearchEngine->SetLevOther( pDlg->GetOther() );
374 m_pSearchEngine->SetLevShorter(pDlg->GetShorter() );
375 m_pSearchEngine->SetLevLonger( pDlg->GetLonger() );
378 else if (m_pSoundsLikeCJKSettings == pButton)
380 SfxItemSet aSet( SfxGetpApp()->GetPool() );
381 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
382 if(pFact)
384 boost::scoped_ptr<AbstractSvxJSearchOptionsDialog> aDlg(pFact->CreateSvxJSearchOptionsDialog( this, aSet, m_pSearchEngine->GetTransliterationFlags() ));
385 DBG_ASSERT(aDlg, "Dialog creation failed!");
386 aDlg->Execute();
389 sal_Int32 nFlags = aDlg->GetTransliterationFlags();
390 m_pSearchEngine->SetTransliterationFlags(nFlags);
392 m_pcbCase->Check(m_pSearchEngine->GetCaseSensitive());
393 OnCheckBoxToggled( m_pcbCase );
394 m_pHalfFullFormsCJK->Check( !m_pSearchEngine->GetIgnoreWidthCJK() );
395 OnCheckBoxToggled( m_pHalfFullFormsCJK );
399 return 0;
402 IMPL_LINK_NOARG(FmSearchDialog, OnSearchTextModified)
404 if ((!m_pcmbSearchText->GetText().isEmpty()) || !m_prbSearchForText->IsChecked())
405 m_pbSearchAgain->Enable();
406 else
407 m_pbSearchAgain->Disable();
409 m_pSearchEngine->InvalidatePreviousLoc();
410 return 0;
413 IMPL_LINK(FmSearchDialog, OnFocusGrabbed, ComboBox*,)
415 m_pcmbSearchText->SetSelection( Selection( SELECTION_MIN, SELECTION_MAX ) );
416 return 0;
419 IMPL_LINK(FmSearchDialog, OnPositionSelected, ListBox*, pBox)
421 (void) pBox; // avoid warning
422 DBG_ASSERT(pBox->GetSelectEntryCount() == 1, "FmSearchDialog::OnMethodSelected : unerwartet : nicht genau ein Eintrag selektiert !");
424 m_pSearchEngine->SetPosition(m_plbPosition->GetSelectEntryPos());
425 return 0;
428 IMPL_LINK(FmSearchDialog, OnFieldSelected, ListBox*, pBox)
430 (void) pBox; // avoid warning
431 DBG_ASSERT(pBox->GetSelectEntryCount() == 1, "FmSearchDialog::OnFieldSelected : unerwartet : nicht genau ein Eintrag selektiert !");
433 m_pSearchEngine->RebuildUsedFields(m_prbAllFields->IsChecked() ? -1 : (sal_Int16)m_plbField->GetSelectEntryPos());
434 // calls m_pSearchEngine->InvalidatePreviousLoc too
436 sal_Int32 nCurrentContext = m_plbForm->GetSelectEntryPos();
437 if (nCurrentContext != LISTBOX_ENTRY_NOTFOUND)
438 m_arrContextFields[nCurrentContext] = OUString(m_plbField->GetSelectEntry());
439 return 0;
442 IMPL_LINK(FmSearchDialog, OnCheckBoxToggled, CheckBox*, pBox)
444 bool bChecked = pBox->IsChecked();
446 // formatter or case -> pass on to the engine
447 if (pBox == m_pcbUseFormat)
448 m_pSearchEngine->SetFormatterUsing(bChecked);
449 else if (pBox == m_pcbCase)
450 m_pSearchEngine->SetCaseSensitive(bChecked);
451 // direction -> pass on and reset the checkbox-text for StartOver
452 else if (pBox == m_pcbBackwards)
454 m_pcbStartOver->SetText( OUString( CUI_RES( bChecked ? RID_STR_FROM_BOTTOM : RID_STR_FROM_TOP ) ) );
455 m_pSearchEngine->SetDirection(!bChecked);
457 // similarity-search or regular expression
458 else if ((pBox == m_pcbApprox) || (pBox == m_pcbRegular) || (pBox == m_pcbWildCard))
460 CheckBox* pBoxes[] = { m_pcbWildCard, m_pcbRegular, m_pcbApprox };
461 for (sal_uInt32 i=0; i< SAL_N_ELEMENTS(pBoxes); ++i)
463 if (pBoxes[i] != pBox)
465 if (bChecked)
466 pBoxes[i]->Disable();
467 else
468 pBoxes[i]->Enable();
472 // pass on to the engine
473 m_pSearchEngine->SetWildcard(m_pcbWildCard->IsEnabled() && m_pcbWildCard->IsChecked());
474 m_pSearchEngine->SetRegular(m_pcbRegular->IsEnabled() && m_pcbRegular->IsChecked());
475 m_pSearchEngine->SetLevenshtein(m_pcbApprox->IsEnabled() && m_pcbApprox->IsChecked());
476 // (disabled boxes have to be passed to the engine as sal_False)
478 // adjust the Position-Listbox (which is not allowed during Wildcard-search)
479 if (pBox == m_pcbWildCard)
481 if (bChecked)
483 m_pftPosition->Disable();
484 m_plbPosition->Disable();
486 else
488 m_pftPosition->Enable();
489 m_plbPosition->Enable();
493 // and the button for similarity-search
494 if (pBox == m_pcbApprox)
496 if (bChecked)
497 m_ppbApproxSettings->Enable();
498 else
499 m_ppbApproxSettings->Disable();
502 else if (pBox == m_pHalfFullFormsCJK)
504 // forward to the search engine
505 m_pSearchEngine->SetIgnoreWidthCJK( !bChecked );
507 else if (pBox == m_pSoundsLikeCJK)
509 m_pSoundsLikeCJKSettings->Enable(bChecked);
511 // two other buttons which depend on this one
512 bool bEnable = ( m_prbSearchForText->IsChecked()
513 && !m_pSoundsLikeCJK->IsChecked()
515 || !SvtCJKOptions().IsJapaneseFindEnabled();
516 m_pcbCase->Enable(bEnable);
517 m_pHalfFullFormsCJK->Enable(bEnable);
519 // forward to the search engine
520 m_pSearchEngine->SetTransliteration( bChecked );
523 return 0;
526 void FmSearchDialog::InitContext(sal_Int16 nContext)
528 FmSearchContext fmscContext;
529 fmscContext.nContext = nContext;
531 #ifdef DBG_UTIL
532 sal_uInt32 nResult =
533 #endif
534 m_lnkContextSupplier.Call(&fmscContext);
535 DBG_ASSERT(nResult > 0, "FmSearchDialog::InitContext : ContextSupplier didn't give me any controls !");
537 // put the field names into the respective listbox
538 m_plbField->Clear();
540 if (!fmscContext.sFieldDisplayNames.isEmpty())
542 // use the display names if supplied
543 DBG_ASSERT(comphelper::string::getTokenCount(fmscContext.sFieldDisplayNames, ';') == comphelper::string::getTokenCount(fmscContext.strUsedFields, ';'),
544 "FmSearchDialog::InitContext : invalid context description supplied !");
545 for (sal_Int32 i=0; i < comphelper::string::getTokenCount(fmscContext.sFieldDisplayNames, ';'); ++i)
546 m_plbField->InsertEntry(fmscContext.sFieldDisplayNames.getToken(i, ';'));
548 else
550 // else use the field names
551 for (sal_Int32 i=0; i < comphelper::string::getTokenCount(fmscContext.strUsedFields, ';'); ++i)
552 m_plbField->InsertEntry(fmscContext.strUsedFields.getToken(i, ';'));
555 if (nContext < (sal_Int32)m_arrContextFields.size() && !m_arrContextFields[nContext].isEmpty())
557 m_plbField->SelectEntry(m_arrContextFields[nContext]);
559 else
561 m_plbField->SelectEntryPos(0);
562 if (m_prbSingleField->IsChecked() && (m_plbField->GetEntryCount() > 1))
563 m_plbField->GrabFocus();
566 m_pSearchEngine->SwitchToContext(fmscContext.xCursor, fmscContext.strUsedFields, fmscContext.arrFields,
567 m_prbAllFields->IsChecked() ? -1 : 0);
569 m_pftRecord->SetText(OUString::number(fmscContext.xCursor->getRow()));
572 IMPL_LINK( FmSearchDialog, OnContextSelection, ListBox*, pBox)
574 InitContext(pBox->GetSelectEntryPos());
575 return 0L;
578 void FmSearchDialog::EnableSearchUI(bool bEnable)
580 // when the controls shall be disabled their paint is turned off and then turned on again after a delay
581 if (!bEnable)
582 EnableControlPaint(false);
583 else
585 if (m_aDelayedPaint.IsActive())
586 m_aDelayedPaint.Stop();
588 // (the whole thing goes on below)
589 // this small intricateness hopfully leads to no flickering when turning the SearchUI off
590 // and on again shortly after (like it's the case during a short search process)
592 if ( !bEnable )
594 // if one of my children has the focus, remember it
595 vcl::Window* pFocusWindow = Application::GetFocusWindow( );
596 if ( pFocusWindow && IsChild( pFocusWindow ) )
597 m_pPreSearchFocus = pFocusWindow;
598 else
599 m_pPreSearchFocus = NULL;
602 // the search button has two functions -> adjust its text accordingly
603 OUString sButtonText( bEnable ? m_sSearch : m_sCancel );
604 m_pbSearchAgain->SetText( sButtonText );
606 if (m_pSearchEngine->GetSearchMode() != SM_BRUTE)
608 m_prbSearchForText->Enable (bEnable);
609 m_prbSearchForNull->Enable (bEnable);
610 m_prbSearchForNotNull->Enable (bEnable);
611 m_plbForm->Enable (bEnable);
612 m_prbAllFields->Enable (bEnable);
613 m_prbSingleField->Enable (bEnable);
614 m_plbField->Enable (bEnable && m_prbSingleField->IsChecked());
615 m_pcbBackwards->Enable (bEnable);
616 m_pcbStartOver->Enable (bEnable);
617 m_pbClose->Enable (bEnable);
618 EnableSearchForDependees (bEnable);
620 if ( !bEnable )
621 { // this means we're preparing for starting a search
622 // In this case, EnableSearchForDependees disabled the search button
623 // But as we're about to use it for cancelling the search, we really need to enable it, again
624 m_pbSearchAgain->Enable( true );
628 if (!bEnable)
629 m_aDelayedPaint.Start();
630 else
631 EnableControlPaint(true);
633 if ( bEnable )
634 { // restore focus
635 if ( m_pPreSearchFocus )
637 m_pPreSearchFocus->GrabFocus();
638 if ( WINDOW_EDIT == m_pPreSearchFocus->GetType() )
640 Edit* pEdit = static_cast< Edit* >( m_pPreSearchFocus.get() );
641 pEdit->SetSelection( Selection( 0, pEdit->GetText().getLength() ) );
644 m_pPreSearchFocus = NULL;
649 void FmSearchDialog::EnableSearchForDependees(bool bEnable)
651 bool bSearchingForText = m_prbSearchForText->IsChecked();
652 m_pbSearchAgain->Enable(bEnable && (!bSearchingForText || (!m_pcmbSearchText->GetText().isEmpty())));
654 bEnable = bEnable && bSearchingForText;
656 bool bEnableRedundants = !m_pSoundsLikeCJK->IsChecked() || !SvtCJKOptions().IsJapaneseFindEnabled();
658 m_pcmbSearchText->Enable (bEnable);
659 m_pftPosition->Enable (bEnable && !m_pcbWildCard->IsChecked());
660 m_pcbWildCard->Enable (bEnable && !m_pcbRegular->IsChecked() && !m_pcbApprox->IsChecked());
661 m_pcbRegular->Enable (bEnable && !m_pcbWildCard->IsChecked() && !m_pcbApprox->IsChecked());
662 m_pcbApprox->Enable (bEnable && !m_pcbWildCard->IsChecked() && !m_pcbRegular->IsChecked());
663 m_ppbApproxSettings->Enable (bEnable && m_pcbApprox->IsChecked());
664 m_pHalfFullFormsCJK->Enable (bEnable && bEnableRedundants);
665 m_pSoundsLikeCJK->Enable (bEnable);
666 m_pSoundsLikeCJKSettings->Enable (bEnable && m_pSoundsLikeCJK->IsChecked());
667 m_plbPosition->Enable (bEnable && !m_pcbWildCard->IsChecked());
668 m_pcbUseFormat->Enable (bEnable);
669 m_pcbCase->Enable (bEnable && bEnableRedundants);
672 void FmSearchDialog::EnableControlPaint(bool bEnable)
674 Control* pAffectedControls[] = { m_prbSearchForText, m_pcmbSearchText, m_prbSearchForNull, m_prbSearchForNotNull,
675 m_prbSearchForText, m_prbAllFields, m_prbSingleField, m_plbField, m_pftPosition, m_plbPosition,
676 m_pcbUseFormat, m_pcbCase, m_pcbBackwards, m_pcbStartOver, m_pcbWildCard, m_pcbRegular, m_pcbApprox, m_ppbApproxSettings,
677 m_pbSearchAgain, m_pbClose };
679 if (!bEnable)
680 for (sal_uInt32 i=0; i<SAL_N_ELEMENTS(pAffectedControls); ++i)
682 pAffectedControls[i]->SetUpdateMode(bEnable);
683 pAffectedControls[i]->EnablePaint(bEnable);
685 else
686 for (sal_uInt32 i=0; i<SAL_N_ELEMENTS(pAffectedControls); ++i)
688 pAffectedControls[i]->EnablePaint(bEnable);
689 pAffectedControls[i]->SetUpdateMode(bEnable);
693 IMPL_LINK_NOARG_TYPED(FmSearchDialog, OnDelayedPaint, Timer *, void)
695 EnableControlPaint(true);
698 void FmSearchDialog::OnFound(const ::com::sun::star::uno::Any& aCursorPos, sal_Int16 nFieldPos)
700 FmFoundRecordInformation friInfo;
701 friInfo.nContext = m_plbForm->GetSelectEntryPos();
702 // if I don't do a search in a context, this has an invalid value - but then it doesn't matter anyway
703 friInfo.aPosition = aCursorPos;
704 if (m_prbAllFields->IsChecked())
705 friInfo.nFieldPos = nFieldPos;
706 else
707 friInfo.nFieldPos = m_plbField->GetSelectEntryPos();
708 // this of course implies that I have really searched in the field that is selected in the listbox,
709 // which is made sure in RebuildUsedFields
711 m_lnkFoundHandler.Call(&friInfo);
713 m_pcmbSearchText->GrabFocus();
716 IMPL_LINK(FmSearchDialog, OnSearchProgress, FmSearchProgress*, pProgress)
718 SolarMutexGuard aGuard;
719 // make this single method thread-safe (it's an overkill to block the whole application for this,
720 // but we don't have another safety concept at the moment)
722 switch (pProgress->aSearchState)
724 case FmSearchProgress::STATE_PROGRESS:
725 if (pProgress->bOverflow)
727 OUString sHint( CUI_RES( m_pcbBackwards->IsChecked() ? RID_STR_OVERFLOW_BACKWARD : RID_STR_OVERFLOW_FORWARD ) );
728 m_pftHint->SetText( sHint );
729 m_pftHint->Invalidate();
732 m_pftRecord->SetText(OUString::number(1 + pProgress->nCurrentRecord));
733 m_pftRecord->Invalidate();
734 break;
736 case FmSearchProgress::STATE_PROGRESS_COUNTING:
737 m_pftHint->SetText(CUI_RESSTR(RID_STR_SEARCH_COUNTING));
738 m_pftHint->Invalidate();
740 m_pftRecord->SetText(OUString::number(pProgress->nCurrentRecord));
741 m_pftRecord->Invalidate();
742 break;
744 case FmSearchProgress::STATE_SUCCESSFULL:
745 OnFound(pProgress->aBookmark, (sal_Int16)pProgress->nFieldIndex);
746 EnableSearchUI(true);
747 break;
749 case FmSearchProgress::STATE_ERROR:
750 case FmSearchProgress::STATE_NOTHINGFOUND:
752 sal_uInt16 nErrorId = (FmSearchProgress::STATE_ERROR == pProgress->aSearchState)
753 ? RID_STR_SEARCH_GENERAL_ERROR
754 : RID_STR_SEARCH_NORECORD;
755 ScopedVclPtrInstance<MessageDialog>::Create(this, CUI_RES(nErrorId))->Execute();
757 // NO break !
758 case FmSearchProgress::STATE_CANCELED:
759 EnableSearchUI(true);
760 if (m_lnkCanceledNotFoundHdl.IsSet())
762 FmFoundRecordInformation friInfo;
763 friInfo.nContext = m_plbForm->GetSelectEntryPos();
764 // if I don't do a search in a context, this has an invalid value - but then it doesn't matter anyway
765 friInfo.aPosition = pProgress->aBookmark;
766 m_lnkCanceledNotFoundHdl.Call(&friInfo);
768 break;
771 m_pftRecord->SetText(OUString::number(1 + pProgress->nCurrentRecord));
773 return 0L;
776 void FmSearchDialog::LoadParams()
778 FmSearchParams aParams(m_pConfig->getParams());
780 const OUString* pHistory = aParams.aHistory.getConstArray();
781 const OUString* pHistoryEnd = pHistory + aParams.aHistory.getLength();
782 for (; pHistory != pHistoryEnd; ++pHistory)
783 m_pcmbSearchText->InsertEntry( *pHistory );
785 // I do the settings at my UI-elements and then I simply call the respective change-handler,
786 // that way the data is handed on to the SearchEngine and all dependent settings are done
788 // current field
789 sal_Int32 nInitialField = m_plbField->GetEntryPos( OUString( aParams.sSingleSearchField ) );
790 if (nInitialField == LISTBOX_ENTRY_NOTFOUND)
791 nInitialField = 0;
792 m_plbField->SelectEntryPos(nInitialField);
793 LINK(this, FmSearchDialog, OnFieldSelected).Call(m_plbField);
794 // all fields/single field (AFTER selcting the field because OnClickedFieldRadios expects a valid value there)
795 if (aParams.bAllFields)
797 m_prbSingleField->Check(false);
798 m_prbAllFields->Check(true);
799 LINK(this, FmSearchDialog, OnClickedFieldRadios).Call(m_prbAllFields);
800 // OnClickedFieldRadios also calls to RebuildUsedFields
802 else
804 m_prbAllFields->Check(false);
805 m_prbSingleField->Check(true);
806 LINK(this, FmSearchDialog, OnClickedFieldRadios).Call(m_prbSingleField);
809 m_plbPosition->SelectEntryPos(aParams.nPosition);
810 LINK(this, FmSearchDialog, OnPositionSelected).Call(m_plbPosition);
812 // field formatting/case sensitivity/direction
813 m_pcbUseFormat->Check(aParams.bUseFormatter);
814 m_pcbCase->Check( aParams.isCaseSensitive() );
815 m_pcbBackwards->Check(aParams.bBackwards);
816 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pcbUseFormat);
817 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pcbCase);
818 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pcbBackwards);
820 m_pHalfFullFormsCJK->Check( !aParams.isIgnoreWidthCJK( ) ); // BEWARE: this checkbox has a inverse semantics!
821 m_pSoundsLikeCJK->Check( aParams.bSoundsLikeCJK );
822 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pHalfFullFormsCJK);
823 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pSoundsLikeCJK);
825 m_pcbWildCard->Check(false);
826 m_pcbRegular->Check(false);
827 m_pcbApprox->Check(false);
828 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pcbWildCard);
829 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pcbRegular);
830 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(m_pcbApprox);
832 CheckBox* pToCheck = NULL;
833 if (aParams.bWildcard)
834 pToCheck = m_pcbWildCard;
835 if (aParams.bRegular)
836 pToCheck = m_pcbRegular;
837 if (aParams.bApproxSearch)
838 pToCheck = m_pcbApprox;
839 if (aParams.bSoundsLikeCJK)
840 pToCheck = m_pSoundsLikeCJK;
841 if (pToCheck)
843 pToCheck->Check(true);
844 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(pToCheck);
847 // set Levenshtein-parameters directly at the SearchEngine
848 m_pSearchEngine->SetLevRelaxed(aParams.bLevRelaxed);
849 m_pSearchEngine->SetLevOther(aParams.nLevOther);
850 m_pSearchEngine->SetLevShorter(aParams.nLevShorter);
851 m_pSearchEngine->SetLevLonger(aParams.nLevLonger);
853 m_pSearchEngine->SetTransliterationFlags( aParams.getTransliterationFlags( ) );
855 m_prbSearchForText->Check(false);
856 m_prbSearchForNull->Check(false);
857 m_prbSearchForNotNull->Check(false);
858 switch (aParams.nSearchForType)
860 case 1: m_prbSearchForNull->Check(true); break;
861 case 2: m_prbSearchForNotNull->Check(true); break;
862 default: m_prbSearchForText->Check(true); break;
864 LINK(this, FmSearchDialog, OnClickedFieldRadios).Call(m_prbSearchForText);
867 void FmSearchDialog::SaveParams() const
869 if (!m_pConfig)
870 return;
872 FmSearchParams aCurrentSettings;
874 aCurrentSettings.aHistory.realloc( m_pcmbSearchText->GetEntryCount() );
875 OUString* pHistory = aCurrentSettings.aHistory.getArray();
876 for (sal_Int32 i=0; i<m_pcmbSearchText->GetEntryCount(); ++i, ++pHistory)
877 *pHistory = m_pcmbSearchText->GetEntry(i);
879 aCurrentSettings.sSingleSearchField = m_plbField->GetSelectEntry();
880 aCurrentSettings.bAllFields = m_prbAllFields->IsChecked();
881 aCurrentSettings.nPosition = m_pSearchEngine->GetPosition();
882 aCurrentSettings.bUseFormatter = m_pSearchEngine->GetFormatterUsing();
883 aCurrentSettings.setCaseSensitive ( m_pSearchEngine->GetCaseSensitive() );
884 aCurrentSettings.bBackwards = !m_pSearchEngine->GetDirection();
885 aCurrentSettings.bWildcard = m_pSearchEngine->GetWildcard();
886 aCurrentSettings.bRegular = m_pSearchEngine->GetRegular();
887 aCurrentSettings.bApproxSearch = m_pSearchEngine->GetLevenshtein();
888 aCurrentSettings.bLevRelaxed = m_pSearchEngine->GetLevRelaxed();
889 aCurrentSettings.nLevOther = m_pSearchEngine->GetLevOther();
890 aCurrentSettings.nLevShorter = m_pSearchEngine->GetLevShorter();
891 aCurrentSettings.nLevLonger = m_pSearchEngine->GetLevLonger();
893 aCurrentSettings.bSoundsLikeCJK = m_pSearchEngine->GetTransliteration();
894 aCurrentSettings.setTransliterationFlags ( m_pSearchEngine->GetTransliterationFlags() );
896 if (m_prbSearchForNull->IsChecked())
897 aCurrentSettings.nSearchForType = 1;
898 else if (m_prbSearchForNotNull->IsChecked())
899 aCurrentSettings.nSearchForType = 2;
900 else
901 aCurrentSettings.nSearchForType = 0;
903 m_pConfig->setParams( aCurrentSettings );
906 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */