update credits
[LibreOffice.git] / cui / source / dialogs / cuifmsearch.cxx
bloba386b9ccaf9601d0a5b3afd56b61c60ec1db324e
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/msgbox.hxx>
22 #include <vcl/svapp.hxx>
23 #include <tools/shl.hxx>
24 #include <dialmgr.hxx>
25 #include <sfx2/tabdlg.hxx>
26 #include <osl/mutex.hxx>
27 #include <sfx2/app.hxx>
28 #include <cuires.hrc>
29 #include <svl/filerec.hxx>
30 #include <svx/fmsrccfg.hxx>
31 #include <svx/fmsrcimp.hxx>
32 #include "fmsearch.hrc"
33 #include "cuifmsearch.hxx"
34 #include <svx/srchdlg.hxx>
35 #include <svl/cjkoptions.hxx>
36 #include <com/sun/star/i18n/TransliterationModules.hpp>
37 #include <comphelper/processfactory.hxx>
38 #include <comphelper/string.hxx>
39 #include <svx/svxdlg.hxx>
40 #include <sal/macros.h>
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::i18n;
44 using namespace ::svxform;
45 using namespace ::com::sun::star::sdbc;
46 using namespace ::com::sun::star::util;
48 #define MAX_HISTORY_ENTRIES 50
50 //------------------------------------------------------------------------
51 void FmSearchDialog::initCommon( const Reference< XResultSet >& _rxCursor )
53 // init the engine
54 DBG_ASSERT( m_pSearchEngine, "FmSearchDialog::initCommon: have no engine!" );
55 m_pSearchEngine->SetProgressHandler(LINK(this, FmSearchDialog, OnSearchProgress));
57 // some layout changes according to available CJK options
58 SvtCJKOptions aCJKOptions;
59 if (!aCJKOptions.IsJapaneseFindEnabled())
61 sal_Int32 nUpper = m_cbApprox.GetPosPixel().Y();
62 sal_Int32 nDifference = m_aSoundsLikeCJKSettings.GetPosPixel().Y() - nUpper;
64 // hide the options for the japanese search
65 Control* pFieldsToMove[] = { &m_flState, &m_ftRecordLabel, &m_ftRecord, &m_ftHint };
66 implMoveControls(pFieldsToMove, SAL_N_ELEMENTS(pFieldsToMove), nDifference, &m_flOptions);
68 m_aSoundsLikeCJK.Hide();
69 m_aSoundsLikeCJKSettings.Hide();
72 if (!aCJKOptions.IsCJKFontEnabled())
74 m_aHalfFullFormsCJK.Hide();
76 // never ignore the width (ignoring is expensive) if the option is not available at all
77 m_pSearchEngine->SetIgnoreWidthCJK( sal_False );
80 // some initial record texts
81 m_ftRecord.SetText( OUString::number(_rxCursor->getRow()) );
82 m_pbClose.SetHelpText(String());
85 //------------------------------------------------------------------------
86 FmSearchDialog::FmSearchDialog(Window* pParent, const OUString& sInitialText, const ::std::vector< OUString >& _rContexts, sal_Int16 nInitialContext,
87 const Link& lnkContextSupplier)
88 :ModalDialog(pParent, CUI_RES(RID_SVXDLG_SEARCHFORM))
89 ,m_flSearchFor (this, CUI_RES(FL_SEARCHFOR))
90 ,m_rbSearchForText (this, CUI_RES(RB_SEARCHFORTEXT))
91 ,m_rbSearchForNull (this, CUI_RES(RB_SEARCHFORNULL))
92 ,m_rbSearchForNotNull (this, CUI_RES(RB_SEARCHFORNOTNULL))
93 ,m_cmbSearchText (this, CUI_RES(CMB_SEARCHTEXT))
94 ,m_flWhere (this, CUI_RES(FL_WHERE))
95 ,m_ftForm (this, CUI_RES(FT_FORM))
96 ,m_lbForm (this, CUI_RES(LB_FORM))
97 ,m_rbAllFields (this, CUI_RES(RB_ALLFIELDS))
98 ,m_rbSingleField (this, CUI_RES(RB_SINGLEFIELD))
99 ,m_lbField (this, CUI_RES(LB_FIELD))
100 ,m_flOptions (this, CUI_RES(FL_OPTIONS))
101 ,m_ftPosition (this, CUI_RES(FT_POSITION))
102 ,m_lbPosition (this, CUI_RES(LB_POSITION))
103 ,m_cbUseFormat (this, CUI_RES(CB_USEFORMATTER))
104 ,m_cbCase (this, CUI_RES(CB_CASE))
105 ,m_cbBackwards (this, CUI_RES(CB_BACKWARD))
106 ,m_cbStartOver (this, CUI_RES(CB_STARTOVER))
107 ,m_cbWildCard (this, CUI_RES(CB_WILDCARD))
108 ,m_cbRegular (this, CUI_RES(CB_REGULAR))
109 ,m_cbApprox (this, CUI_RES(CB_APPROX))
110 ,m_pbApproxSettings (this, CUI_RES(PB_APPROXSETTINGS))
111 ,m_aHalfFullFormsCJK (this, CUI_RES(CB_HALFFULLFORMS))
112 ,m_aSoundsLikeCJK (this, CUI_RES(CB_SOUNDSLIKECJK))
113 ,m_aSoundsLikeCJKSettings (this, CUI_RES(PB_SOUNDSLIKESETTINGS))
114 ,m_flState (this, CUI_RES(FL_STATE))
115 ,m_ftRecordLabel (this, CUI_RES(FT_RECORDLABEL))
116 ,m_ftRecord (this, CUI_RES(FT_RECORD))
117 ,m_ftHint (this, CUI_RES(FT_HINT))
118 ,m_pbSearchAgain (this, CUI_RES(PB_SEARCH))
119 ,m_pbClose (this, CUI_RES(1))
120 ,m_pbHelp (this, CUI_RES(1))
121 ,m_sSearch ( m_pbSearchAgain.GetText() )
122 ,m_sCancel ( Button::GetStandardText( BUTTON_CANCEL ) )
123 ,m_pPreSearchFocus( NULL )
124 ,m_lnkContextSupplier(lnkContextSupplier)
125 ,m_pConfig( NULL )
127 DBG_ASSERT(m_lnkContextSupplier.IsSet(), "FmSearchDialog::FmSearchDialog : have no ContextSupplier !");
129 FmSearchContext fmscInitial;
130 fmscInitial.nContext = nInitialContext;
131 m_lnkContextSupplier.Call(&fmscInitial);
132 DBG_ASSERT(fmscInitial.xCursor.is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
133 DBG_ASSERT(comphelper::string::getTokenCount(fmscInitial.strUsedFields, ';') == (xub_StrLen)fmscInitial.arrFields.size(),
134 "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplied !");
135 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
136 for (sal_Int32 i=0; i<(sal_Int32)fmscInitial.arrFields.size(); ++i)
137 DBG_ASSERT(fmscInitial.arrFields.at(i).is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
138 #endif // (OSL_DEBUG_LEVEL > 1) || DBG_UTIL
140 for ( ::std::vector< OUString >::const_iterator context = _rContexts.begin();
141 context != _rContexts.end();
142 ++context
145 m_arrContextFields.push_back(OUString());
146 m_lbForm.InsertEntry(*context);
148 m_lbForm.SelectEntryPos(nInitialContext);
150 m_lbForm.SetSelectHdl(LINK(this, FmSearchDialog, OnContextSelection));
152 if (m_arrContextFields.size() == 1)
153 { // remove the context selection listbox and rearrange the controls accordingly
154 sal_Int32 nUpper = m_lbForm.GetPosPixel().Y();
155 sal_Int32 nDifference = m_rbAllFields.GetPosPixel().Y() - nUpper;
157 // move all controls below the affected ones up
158 Control* pFieldsToMove[] = { &m_rbAllFields, &m_rbSingleField, &m_lbField, &m_flOptions, &m_ftPosition, &m_lbPosition,
159 &m_cbUseFormat, &m_cbCase, &m_cbBackwards, &m_cbStartOver, &m_cbWildCard, &m_cbRegular, &m_cbApprox,
160 &m_pbApproxSettings, &m_aHalfFullFormsCJK, &m_aSoundsLikeCJK, &m_aSoundsLikeCJKSettings,
161 &m_flState, &m_ftRecordLabel, &m_ftRecord, &m_ftHint };
163 implMoveControls(pFieldsToMove, SAL_N_ELEMENTS(pFieldsToMove), nDifference, &m_flWhere);
165 Point pt = m_rbAllFields.GetPosPixel();
166 pt.X() = m_ftForm.GetPosPixel().X();
167 m_rbAllFields.SetPosPixel( pt );
168 pt = m_rbSingleField.GetPosPixel();
169 pt.X() = m_ftForm.GetPosPixel().X();
170 m_rbSingleField.SetPosPixel( pt );
172 // hide dispensable controls
173 m_ftForm.Hide();
174 m_lbForm.Hide();
177 m_pSearchEngine = new FmSearchEngine(
178 ::comphelper::getProcessComponentContext(), fmscInitial.xCursor, fmscInitial.strUsedFields, fmscInitial.arrFields, SM_ALLOWSCHEDULE );
179 initCommon( fmscInitial.xCursor );
181 if (fmscInitial.sFieldDisplayNames.Len() != 0)
182 { // use the display names if supplied
183 DBG_ASSERT(comphelper::string::getTokenCount(fmscInitial.sFieldDisplayNames, ';') == comphelper::string::getTokenCount(fmscInitial.strUsedFields, ';'),
184 "FmSearchDialog::FmSearchDialog : invalid initial context description !");
185 Init(fmscInitial.sFieldDisplayNames, sInitialText);
187 else
188 Init(fmscInitial.strUsedFields, sInitialText);
191 //------------------------------------------------------------------------
192 void FmSearchDialog::implMoveControls(
193 Control** _ppControls,
194 sal_Int32 _nControls,
195 sal_Int32 _nUp,
196 Control* /*_pToResize*/)
198 for (sal_Int32 i=0; i<_nControls; ++i)
200 Point pt = _ppControls[i]->GetPosPixel();
201 pt.Y() -= _nUp;
202 _ppControls[i]->SetPosPixel(pt);
205 // resize myself
206 Size sz = GetSizePixel();
207 sz.Height() -= _nUp;
208 SetSizePixel(sz);
211 //------------------------------------------------------------------------
212 FmSearchDialog::~FmSearchDialog()
214 if (m_aDelayedPaint.IsActive())
215 m_aDelayedPaint.Stop();
217 SaveParams();
219 if (m_pConfig)
221 delete m_pConfig;
222 m_pConfig = NULL;
225 delete m_pSearchEngine;
228 //------------------------------------------------------------------------
229 void FmSearchDialog::Init(const OUString& strVisibleFields, const OUString& sInitialText)
231 //the initialization of all the Controls
232 m_rbSearchForText.SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
233 m_rbSearchForNull.SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
234 m_rbSearchForNotNull.SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
236 m_rbAllFields.SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
237 m_rbSingleField.SetClickHdl(LINK(this, FmSearchDialog, OnClickedFieldRadios));
239 m_pbSearchAgain.SetClickHdl(LINK(this, FmSearchDialog, OnClickedSearchAgain));
240 m_pbApproxSettings.SetClickHdl(LINK(this, FmSearchDialog, OnClickedSpecialSettings));
241 m_aSoundsLikeCJKSettings.SetClickHdl(LINK(this, FmSearchDialog, OnClickedSpecialSettings));
243 m_lbPosition.SetSelectHdl(LINK(this, FmSearchDialog, OnPositionSelected));
244 m_lbField.SetSelectHdl(LINK(this, FmSearchDialog, OnFieldSelected));
246 m_cmbSearchText.SetModifyHdl(LINK(this, FmSearchDialog, OnSearchTextModified));
247 m_cmbSearchText.EnableAutocomplete(sal_False);
249 m_cbUseFormat.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
250 m_cbBackwards.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
251 m_cbStartOver.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
252 m_cbCase.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
253 m_cbWildCard.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
254 m_cbRegular.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
255 m_cbApprox.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
256 m_aHalfFullFormsCJK.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
257 m_aSoundsLikeCJK.SetToggleHdl(LINK(this, FmSearchDialog, OnCheckBoxToggled));
259 // fill the listboxes
260 // method of field comparison
261 sal_uInt16 nResIds[] = {
262 RID_STR_SEARCH_ANYWHERE,
263 RID_STR_SEARCH_BEGINNING,
264 RID_STR_SEARCH_END,
265 RID_STR_SEARCH_WHOLE
267 for ( size_t i=0; i<SAL_N_ELEMENTS(nResIds); ++i )
268 m_lbPosition.InsertEntry( String( CUI_RES( nResIds[i] ) ) );
269 m_lbPosition.SelectEntryPos(MATCHING_ANYWHERE);
271 // the field listbox
272 for (sal_Int32 i=0; i < comphelper::string::getTokenCount(strVisibleFields, ';'); ++i)
273 m_lbField.InsertEntry(comphelper::string::getToken(strVisibleFields, i, ';'));
276 m_pConfig = new FmSearchConfigItem;
277 LoadParams();
279 m_cmbSearchText.SetText(sInitialText);
280 // if the Edit-line has changed the text (e.g. because it contains
281 // control characters, as can be the case with memo fields), I use
282 // an empty OUString.
283 OUString sRealSetText = m_cmbSearchText.GetText();
284 if (!sRealSetText.equals(sInitialText))
285 m_cmbSearchText.SetText(OUString());
286 LINK(this, FmSearchDialog, OnSearchTextModified).Call(&m_cmbSearchText);
288 // initial
289 m_aDelayedPaint.SetTimeoutHdl(LINK(this, FmSearchDialog, OnDelayedPaint));
290 m_aDelayedPaint.SetTimeout(500);
291 EnableSearchUI(sal_True);
293 if ( m_rbSearchForText.IsChecked() )
294 m_cmbSearchText.GrabFocus();
296 FreeResource();
299 //------------------------------------------------------------------------
300 sal_Bool FmSearchDialog::Close()
302 // If the close button is disabled and ESC is pressed in a dialog,
303 // then Frame will call Close anyway, which I don't want to happen
304 // while I'm in the middle of a search (maybe one that's running
305 // in its own thread)
306 if (!m_pbClose.IsEnabled())
307 return sal_False;
308 return ModalDialog::Close();
311 //------------------------------------------------------------------------
312 IMPL_LINK(FmSearchDialog, OnClickedFieldRadios, Button*, pButton)
314 if ((pButton == &m_rbSearchForText) || (pButton == &m_rbSearchForNull) || (pButton == &m_rbSearchForNotNull))
316 EnableSearchForDependees(sal_True);
318 else
319 // en- or disable field list box accordingly
320 if (pButton == &m_rbSingleField)
322 m_lbField.Enable();
323 m_pSearchEngine->RebuildUsedFields(m_lbField.GetSelectEntryPos());
325 else
327 m_lbField.Disable();
328 m_pSearchEngine->RebuildUsedFields(-1);
331 return 0;
334 //------------------------------------------------------------------------
335 IMPL_LINK_NOARG(FmSearchDialog, OnClickedSearchAgain)
337 if (m_pbClose.IsEnabled())
338 { // the button has the function 'search'
339 OUString strThisRoundText = m_cmbSearchText.GetText();
340 // to history
341 m_cmbSearchText.RemoveEntry(strThisRoundText);
342 m_cmbSearchText.InsertEntry(strThisRoundText, 0);
343 // the remove/insert makes sure that a) the OUString does not appear twice and
344 // that b) the last searched strings are at the beginning and limit the list length
345 while (m_cmbSearchText.GetEntryCount() > MAX_HISTORY_ENTRIES)
346 m_cmbSearchText.RemoveEntry(m_cmbSearchText.GetEntryCount()-1);
348 // take out the 'overflow' hint
349 m_ftHint.SetText(OUString());
350 m_ftHint.Invalidate();
352 if (m_cbStartOver.IsChecked())
354 m_cbStartOver.Check(sal_False);
355 EnableSearchUI(sal_False);
356 if (m_rbSearchForText.IsChecked())
357 m_pSearchEngine->StartOver(strThisRoundText);
358 else
359 m_pSearchEngine->StartOverSpecial(m_rbSearchForNull.IsChecked());
361 else
363 EnableSearchUI(sal_False);
364 if (m_rbSearchForText.IsChecked())
365 m_pSearchEngine->SearchNext(strThisRoundText);
366 else
367 m_pSearchEngine->SearchNextSpecial(m_rbSearchForNull.IsChecked());
370 else
371 { // the button has the function 'cancel'
372 DBG_ASSERT(m_pSearchEngine->GetSearchMode() != SM_BRUTE, "FmSearchDialog, OnClickedSearchAgain : falscher Modus !");
373 // the CancelButton is usually only disabled, when working in a thread or with reschedule
374 m_pSearchEngine->CancelSearch();
375 // the ProgressHandler is called when it's really finished, here it's only a demand
377 return 0;
380 //------------------------------------------------------------------------
381 IMPL_LINK(FmSearchDialog, OnClickedSpecialSettings, Button*, pButton )
383 if (&m_pbApproxSettings == pButton)
385 AbstractSvxSearchSimilarityDialog* pDlg = NULL;
387 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
388 if ( pFact )
389 pDlg = pFact->CreateSvxSearchSimilarityDialog( this, m_pSearchEngine->GetLevRelaxed(), m_pSearchEngine->GetLevOther(),
390 m_pSearchEngine->GetLevShorter(), m_pSearchEngine->GetLevLonger() );
391 DBG_ASSERT( pDlg, "FmSearchDialog, OnClickedSpecialSettings: could not load the dialog!" );
393 if ( pDlg && pDlg->Execute() == RET_OK )
395 m_pSearchEngine->SetLevRelaxed( pDlg->IsRelaxed() );
396 m_pSearchEngine->SetLevOther( pDlg->GetOther() );
397 m_pSearchEngine->SetLevShorter(pDlg->GetShorter() );
398 m_pSearchEngine->SetLevLonger( pDlg->GetLonger() );
400 delete pDlg;
402 else if (&m_aSoundsLikeCJKSettings == pButton)
404 SfxItemSet aSet( SFX_APP()->GetPool() );
405 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
406 if(pFact)
408 AbstractSvxJSearchOptionsDialog* aDlg = pFact->CreateSvxJSearchOptionsDialog( this, aSet, m_pSearchEngine->GetTransliterationFlags() );
409 DBG_ASSERT(aDlg, "Dialogdiet fail!");
410 aDlg->Execute();
413 sal_Int32 nFlags = aDlg->GetTransliterationFlags();
414 m_pSearchEngine->SetTransliterationFlags(nFlags);
416 m_cbCase.Check(m_pSearchEngine->GetCaseSensitive());
417 OnCheckBoxToggled( &m_cbCase );
418 m_aHalfFullFormsCJK.Check( !m_pSearchEngine->GetIgnoreWidthCJK() );
419 OnCheckBoxToggled( &m_aHalfFullFormsCJK );
420 delete aDlg;
424 return 0;
427 //------------------------------------------------------------------------
428 IMPL_LINK_NOARG(FmSearchDialog, OnSearchTextModified)
430 if ((!m_cmbSearchText.GetText().isEmpty()) || !m_rbSearchForText.IsChecked())
431 m_pbSearchAgain.Enable();
432 else
433 m_pbSearchAgain.Disable();
435 m_pSearchEngine->InvalidatePreviousLoc();
436 return 0;
439 //------------------------------------------------------------------------
440 IMPL_LINK(FmSearchDialog, OnPositionSelected, ListBox*, pBox)
442 (void) pBox; // avoid warning
443 DBG_ASSERT(pBox->GetSelectEntryCount() == 1, "FmSearchDialog::OnMethodSelected : unerwartet : nicht genau ein Eintrag selektiert !");
445 m_pSearchEngine->SetPosition(m_lbPosition.GetSelectEntryPos());
446 return 0;
449 //------------------------------------------------------------------------
450 IMPL_LINK(FmSearchDialog, OnFieldSelected, ListBox*, pBox)
452 (void) pBox; // avoid warning
453 DBG_ASSERT(pBox->GetSelectEntryCount() == 1, "FmSearchDialog::OnFieldSelected : unerwartet : nicht genau ein Eintrag selektiert !");
455 m_pSearchEngine->RebuildUsedFields(m_rbAllFields.IsChecked() ? -1 : (sal_Int16)m_lbField.GetSelectEntryPos());
456 // calls m_pSearchEngine->InvalidatePreviousLoc too
458 sal_Int32 nCurrentContext = m_lbForm.GetSelectEntryPos();
459 if (nCurrentContext != LISTBOX_ENTRY_NOTFOUND)
460 m_arrContextFields[nCurrentContext] = OUString(m_lbField.GetSelectEntry());
461 return 0;
464 //------------------------------------------------------------------------
465 IMPL_LINK(FmSearchDialog, OnCheckBoxToggled, CheckBox*, pBox)
467 sal_Bool bChecked = pBox->IsChecked();
469 // formatter or case -> pass on to the engine
470 if (pBox == &m_cbUseFormat)
471 m_pSearchEngine->SetFormatterUsing(bChecked);
472 else if (pBox == &m_cbCase)
473 m_pSearchEngine->SetCaseSensitive(bChecked);
474 // direction -> pass on and reset the checkbox-text for StartOver
475 else if (pBox == &m_cbBackwards)
477 m_cbStartOver.SetText( OUString( CUI_RES( bChecked ? RID_STR_FROM_BOTTOM : RID_STR_FROM_TOP ) ) );
478 m_pSearchEngine->SetDirection(!bChecked);
480 // similarity-search or regular expression
481 else if ((pBox == &m_cbApprox) || (pBox == &m_cbRegular) || (pBox == &m_cbWildCard))
483 CheckBox* pBoxes[] = { &m_cbWildCard, &m_cbRegular, &m_cbApprox };
484 for (sal_uInt32 i=0; i< SAL_N_ELEMENTS(pBoxes); ++i)
486 if (pBoxes[i] != pBox)
488 if (bChecked)
489 pBoxes[i]->Disable();
490 else
491 pBoxes[i]->Enable();
495 // pass on to the engine
496 m_pSearchEngine->SetWildcard(m_cbWildCard.IsEnabled() ? m_cbWildCard.IsChecked() : sal_False);
497 m_pSearchEngine->SetRegular(m_cbRegular.IsEnabled() ? m_cbRegular.IsChecked() : sal_False);
498 m_pSearchEngine->SetLevenshtein(m_cbApprox.IsEnabled() ? m_cbApprox.IsChecked() : sal_False);
499 // (disabled boxes have to be passed to the engine as sal_False)
501 // adjust the Position-Listbox (which is not allowed during Wildcard-search)
502 if (pBox == &m_cbWildCard)
504 if (bChecked)
506 m_ftPosition.Disable();
507 m_lbPosition.Disable();
509 else
511 m_ftPosition.Enable();
512 m_lbPosition.Enable();
516 // and the button for similarity-search
517 if (pBox == &m_cbApprox)
519 if (bChecked)
520 m_pbApproxSettings.Enable();
521 else
522 m_pbApproxSettings.Disable();
525 else if (pBox == &m_aHalfFullFormsCJK)
527 // forward to the search engine
528 m_pSearchEngine->SetIgnoreWidthCJK( !bChecked );
530 else if (pBox == &m_aSoundsLikeCJK)
532 m_aSoundsLikeCJKSettings.Enable(bChecked);
534 // two other buttons which depend on this one
535 sal_Bool bEnable = ( m_rbSearchForText.IsChecked()
536 && !m_aSoundsLikeCJK.IsChecked()
538 || !SvtCJKOptions().IsJapaneseFindEnabled();
539 m_cbCase.Enable(bEnable);
540 m_aHalfFullFormsCJK.Enable(bEnable);
542 // forward to the search engine
543 m_pSearchEngine->SetTransliteration( bChecked );
546 return 0;
549 //------------------------------------------------------------------------
550 void FmSearchDialog::InitContext(sal_Int16 nContext)
552 FmSearchContext fmscContext;
553 fmscContext.nContext = nContext;
555 #ifdef DBG_UTIL
556 sal_uInt32 nResult =
557 #endif
558 m_lnkContextSupplier.Call(&fmscContext);
559 DBG_ASSERT(nResult > 0, "FmSearchDialog::InitContext : ContextSupplier didn't give me any controls !");
561 // put the field names into the respective listbox
562 m_lbField.Clear();
564 if (fmscContext.sFieldDisplayNames.Len() != 0)
566 // use the display names if supplied
567 DBG_ASSERT(comphelper::string::getTokenCount(fmscContext.sFieldDisplayNames, ';') == comphelper::string::getTokenCount(fmscContext.strUsedFields, ';'),
568 "FmSearchDialog::InitContext : invalid context description supplied !");
569 for (sal_Int32 i=0; i < comphelper::string::getTokenCount(fmscContext.sFieldDisplayNames, ';'); ++i)
570 m_lbField.InsertEntry(comphelper::string::getToken(fmscContext.sFieldDisplayNames, i, ';'));
572 else
574 // else use the field names
575 for (sal_Int32 i=0; i < comphelper::string::getTokenCount(fmscContext.strUsedFields, ';'); ++i)
576 m_lbField.InsertEntry(comphelper::string::getToken(fmscContext.strUsedFields, i, ';'));
579 if (nContext < (sal_Int32)m_arrContextFields.size() && m_arrContextFields[nContext].Len())
581 m_lbField.SelectEntry(m_arrContextFields[nContext]);
583 else
585 m_lbField.SelectEntryPos(0);
586 if (m_rbSingleField.IsChecked() && (m_lbField.GetEntryCount() > 1))
587 m_lbField.GrabFocus();
590 m_pSearchEngine->SwitchToContext(fmscContext.xCursor, fmscContext.strUsedFields, fmscContext.arrFields,
591 m_rbAllFields.IsChecked() ? -1 : 0);
593 m_ftRecord.SetText(OUString::number(fmscContext.xCursor->getRow()));
596 //------------------------------------------------------------------------
597 IMPL_LINK( FmSearchDialog, OnContextSelection, ListBox*, pBox)
599 InitContext(pBox->GetSelectEntryPos());
600 return 0L;
603 //------------------------------------------------------------------------
604 void FmSearchDialog::EnableSearchUI(sal_Bool bEnable)
606 // when the controls shall be disabled their paint is turned off and then turned on again after a delay
607 if (!bEnable)
608 EnableControlPaint(sal_False);
609 else
611 if (m_aDelayedPaint.IsActive())
612 m_aDelayedPaint.Stop();
614 // (the whole thing goes on below)
615 // this small intricateness hopfully leads to no flickering when turning the SearchUI off
616 // and on again shortly after (like it's the case during a short search process)
618 if ( !bEnable )
620 // if one of my children has the focus, remember it
621 Window* pFocusWindow = Application::GetFocusWindow( );
622 if ( pFocusWindow && IsChild( pFocusWindow ) )
623 m_pPreSearchFocus = pFocusWindow;
624 else
625 m_pPreSearchFocus = NULL;
628 // the search button has two functions -> adjust its text accordingly
629 OUString sButtonText( bEnable ? m_sSearch : m_sCancel );
630 m_pbSearchAgain.SetText( sButtonText );
632 if (m_pSearchEngine->GetSearchMode() != SM_BRUTE)
634 m_flSearchFor.Enable (bEnable);
635 m_rbSearchForText.Enable (bEnable);
636 m_rbSearchForNull.Enable (bEnable);
637 m_rbSearchForNotNull.Enable (bEnable);
638 m_flWhere.Enable (bEnable);
639 m_ftForm.Enable (bEnable);
640 m_lbForm.Enable (bEnable);
641 m_rbAllFields.Enable (bEnable);
642 m_rbSingleField.Enable (bEnable);
643 m_lbField.Enable (bEnable && m_rbSingleField.IsChecked());
644 m_flOptions.Enable (bEnable);
645 m_cbBackwards.Enable (bEnable);
646 m_cbStartOver.Enable (bEnable);
647 m_pbClose.Enable (bEnable);
648 EnableSearchForDependees (bEnable);
650 if ( !bEnable )
651 { // this means we're preparing for starting a search
652 // In this case, EnableSearchForDependees disabled the search button
653 // But as we're about to use it for cancelling the search, we really need to enable it, again
654 m_pbSearchAgain.Enable( sal_True );
658 if (!bEnable)
659 m_aDelayedPaint.Start();
660 else
661 EnableControlPaint(sal_True);
663 if ( bEnable )
664 { // restore focus
665 if ( m_pPreSearchFocus )
667 m_pPreSearchFocus->GrabFocus();
668 if ( WINDOW_EDIT == m_pPreSearchFocus->GetType() )
670 Edit* pEdit = static_cast< Edit* >( m_pPreSearchFocus );
671 pEdit->SetSelection( Selection( 0, pEdit->GetText().getLength() ) );
674 m_pPreSearchFocus = NULL;
679 //------------------------------------------------------------------------
680 void FmSearchDialog::EnableSearchForDependees(sal_Bool bEnable)
682 sal_Bool bSearchingForText = m_rbSearchForText.IsChecked();
683 m_pbSearchAgain.Enable(bEnable && (!bSearchingForText || (!m_cmbSearchText.GetText().isEmpty())));
685 bEnable = bEnable && bSearchingForText;
687 sal_Bool bEnableRedundants = !m_aSoundsLikeCJK.IsChecked() || !SvtCJKOptions().IsJapaneseFindEnabled();
689 m_cmbSearchText.Enable (bEnable);
690 m_ftPosition.Enable (bEnable && !m_cbWildCard.IsChecked());
691 m_cbWildCard.Enable (bEnable && !m_cbRegular.IsChecked() && !m_cbApprox.IsChecked());
692 m_cbRegular.Enable (bEnable && !m_cbWildCard.IsChecked() && !m_cbApprox.IsChecked());
693 m_cbApprox.Enable (bEnable && !m_cbWildCard.IsChecked() && !m_cbRegular.IsChecked());
694 m_pbApproxSettings.Enable (bEnable && m_cbApprox.IsChecked());
695 m_aHalfFullFormsCJK.Enable (bEnable && bEnableRedundants);
696 m_aSoundsLikeCJK.Enable (bEnable);
697 m_aSoundsLikeCJKSettings.Enable (bEnable && m_aSoundsLikeCJK.IsChecked());
698 m_lbPosition.Enable (bEnable && !m_cbWildCard.IsChecked());
699 m_cbUseFormat.Enable (bEnable);
700 m_cbCase.Enable (bEnable && bEnableRedundants);
703 //------------------------------------------------------------------------
704 void FmSearchDialog::EnableControlPaint(sal_Bool bEnable)
706 Control* pAffectedControls[] = { &m_flSearchFor, &m_rbSearchForText, &m_cmbSearchText, &m_rbSearchForNull, &m_rbSearchForNotNull,
707 &m_rbSearchForText, &m_flWhere, &m_rbAllFields, &m_rbSingleField, &m_lbField, &m_flOptions, &m_ftPosition, &m_lbPosition,
708 &m_cbUseFormat, &m_cbCase, &m_cbBackwards, &m_cbStartOver, &m_cbWildCard, &m_cbRegular, &m_cbApprox, &m_pbApproxSettings,
709 &m_pbSearchAgain, &m_pbClose };
711 if (!bEnable)
712 for (sal_uInt32 i=0; i<SAL_N_ELEMENTS(pAffectedControls); ++i)
714 pAffectedControls[i]->SetUpdateMode(bEnable);
715 pAffectedControls[i]->EnablePaint(bEnable);
717 else
718 for (sal_uInt32 i=0; i<SAL_N_ELEMENTS(pAffectedControls); ++i)
720 pAffectedControls[i]->EnablePaint(bEnable);
721 pAffectedControls[i]->SetUpdateMode(bEnable);
725 //------------------------------------------------------------------------
726 IMPL_LINK_NOARG(FmSearchDialog, OnDelayedPaint)
728 EnableControlPaint(sal_True);
729 return 0L;
732 //------------------------------------------------------------------------
733 void FmSearchDialog::OnFound(const ::com::sun::star::uno::Any& aCursorPos, sal_Int16 nFieldPos)
735 FmFoundRecordInformation friInfo;
736 friInfo.nContext = m_lbForm.GetSelectEntryPos();
737 // if I don't do a search in a context, this has an invalid value - but then it doesn't matter anyway
738 friInfo.aPosition = aCursorPos;
739 if (m_rbAllFields.IsChecked())
740 friInfo.nFieldPos = nFieldPos;
741 else
742 friInfo.nFieldPos = m_lbField.GetSelectEntryPos();
743 // this of course implies that I have really searched in the field that is selected in the listbox,
744 // which is made sure in RebuildUsedFields
746 m_lnkFoundHandler.Call(&friInfo);
748 m_cmbSearchText.GrabFocus();
751 //------------------------------------------------------------------------
752 IMPL_LINK(FmSearchDialog, OnSearchProgress, FmSearchProgress*, pProgress)
754 SolarMutexGuard aGuard;
755 // make this single method thread-safe (it's an overkill to block the whole application for this,
756 // but we don't have another safety concept at the moment)
758 switch (pProgress->aSearchState)
760 case FmSearchProgress::STATE_PROGRESS:
761 if (pProgress->bOverflow)
763 OUString sHint( CUI_RES( m_cbBackwards.IsChecked() ? RID_STR_OVERFLOW_BACKWARD : RID_STR_OVERFLOW_FORWARD ) );
764 m_ftHint.SetText( sHint );
765 m_ftHint.Invalidate();
768 m_ftRecord.SetText(OUString::number(1 + pProgress->nCurrentRecord));
769 m_ftRecord.Invalidate();
770 break;
772 case FmSearchProgress::STATE_PROGRESS_COUNTING:
773 m_ftHint.SetText(CUI_RESSTR(RID_STR_SEARCH_COUNTING));
774 m_ftHint.Invalidate();
776 m_ftRecord.SetText(OUString::number(pProgress->nCurrentRecord));
777 m_ftRecord.Invalidate();
778 break;
780 case FmSearchProgress::STATE_SUCCESSFULL:
781 OnFound(pProgress->aBookmark, (sal_Int16)pProgress->nFieldIndex);
782 EnableSearchUI(sal_True);
783 break;
785 case FmSearchProgress::STATE_ERROR:
786 case FmSearchProgress::STATE_NOTHINGFOUND:
788 sal_uInt16 nErrorId = (FmSearchProgress::STATE_ERROR == pProgress->aSearchState)
789 ? RID_SVXERR_SEARCH_GENERAL_ERROR
790 : RID_SVXERR_SEARCH_NORECORD;
791 ErrorBox(this, CUI_RES(nErrorId)).Execute();
793 // NO break !
794 case FmSearchProgress::STATE_CANCELED:
795 EnableSearchUI(sal_True);
796 if (m_lnkCanceledNotFoundHdl.IsSet())
798 FmFoundRecordInformation friInfo;
799 friInfo.nContext = m_lbForm.GetSelectEntryPos();
800 // if I don't do a search in a context, this has an invalid value - but then it doesn't matter anyway
801 friInfo.aPosition = pProgress->aBookmark;
802 m_lnkCanceledNotFoundHdl.Call(&friInfo);
804 break;
807 m_ftRecord.SetText(OUString::number(1 + pProgress->nCurrentRecord));
809 return 0L;
812 //------------------------------------------------------------------------
813 void FmSearchDialog::LoadParams()
815 FmSearchParams aParams(m_pConfig->getParams());
817 const OUString* pHistory = aParams.aHistory.getConstArray();
818 const OUString* pHistoryEnd = pHistory + aParams.aHistory.getLength();
819 for (; pHistory != pHistoryEnd; ++pHistory)
820 m_cmbSearchText.InsertEntry( *pHistory );
822 // I do the settings at my UI-elements and then I simply call the respective change-handler,
823 // that way the data is handed on to the SearchEngine and all dependent settings are done
825 // current field
826 sal_uInt16 nInitialField = m_lbField.GetEntryPos( String( aParams.sSingleSearchField ) );
827 if (nInitialField == COMBOBOX_ENTRY_NOTFOUND)
828 nInitialField = 0;
829 m_lbField.SelectEntryPos(nInitialField);
830 LINK(this, FmSearchDialog, OnFieldSelected).Call(&m_lbField);
831 // all fields/single field (AFTER selcting the field because OnClickedFieldRadios expects a valid value there)
832 if (aParams.bAllFields)
834 m_rbSingleField.Check(sal_False);
835 m_rbAllFields.Check(sal_True);
836 LINK(this, FmSearchDialog, OnClickedFieldRadios).Call(&m_rbAllFields);
837 // OnClickedFieldRadios also calls to RebuildUsedFields
839 else
841 m_rbAllFields.Check(sal_False);
842 m_rbSingleField.Check(sal_True);
843 LINK(this, FmSearchDialog, OnClickedFieldRadios).Call(&m_rbSingleField);
846 m_lbPosition.SelectEntryPos(aParams.nPosition);
847 LINK(this, FmSearchDialog, OnPositionSelected).Call(&m_lbPosition);
849 // field formatting/case sensitivity/direction
850 m_cbUseFormat.Check(aParams.bUseFormatter);
851 m_cbCase.Check( aParams.isCaseSensitive() );
852 m_cbBackwards.Check(aParams.bBackwards);
853 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_cbUseFormat);
854 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_cbCase);
855 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_cbBackwards);
857 m_aHalfFullFormsCJK.Check( !aParams.isIgnoreWidthCJK( ) ); // BEWARE: this checkbox has a inverse semantics!
858 m_aSoundsLikeCJK.Check( aParams.bSoundsLikeCJK );
859 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_aHalfFullFormsCJK);
860 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_aSoundsLikeCJK);
862 m_cbWildCard.Check(sal_False);
863 m_cbRegular.Check(sal_False);
864 m_cbApprox.Check(sal_False);
865 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_cbWildCard);
866 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_cbRegular);
867 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(&m_cbApprox);
869 CheckBox* pToCheck = NULL;
870 if (aParams.bWildcard)
871 pToCheck = &m_cbWildCard;
872 if (aParams.bRegular)
873 pToCheck = &m_cbRegular;
874 if (aParams.bApproxSearch)
875 pToCheck = &m_cbApprox;
876 if (aParams.bSoundsLikeCJK)
877 pToCheck = &m_aSoundsLikeCJK;
878 if (pToCheck)
880 pToCheck->Check(sal_True);
881 LINK(this, FmSearchDialog, OnCheckBoxToggled).Call(pToCheck);
884 // set Levenshtein-parameters directly at the SearchEngine
885 m_pSearchEngine->SetLevRelaxed(aParams.bLevRelaxed);
886 m_pSearchEngine->SetLevOther(aParams.nLevOther);
887 m_pSearchEngine->SetLevShorter(aParams.nLevShorter);
888 m_pSearchEngine->SetLevLonger(aParams.nLevLonger);
890 m_pSearchEngine->SetTransliterationFlags( aParams.getTransliterationFlags( ) );
892 m_rbSearchForText.Check(sal_False);
893 m_rbSearchForNull.Check(sal_False);
894 m_rbSearchForNotNull.Check(sal_False);
895 switch (aParams.nSearchForType)
897 case 1: m_rbSearchForNull.Check(sal_True); break;
898 case 2: m_rbSearchForNotNull.Check(sal_True); break;
899 default: m_rbSearchForText.Check(sal_True); break;
901 LINK(this, FmSearchDialog, OnClickedFieldRadios).Call(&m_rbSearchForText);
904 //------------------------------------------------------------------------
905 void FmSearchDialog::SaveParams() const
907 if (!m_pConfig)
908 return;
910 FmSearchParams aCurrentSettings;
912 aCurrentSettings.aHistory.realloc( m_cmbSearchText.GetEntryCount() );
913 OUString* pHistory = aCurrentSettings.aHistory.getArray();
914 for (sal_uInt16 i=0; i<m_cmbSearchText.GetEntryCount(); ++i, ++pHistory)
915 *pHistory = m_cmbSearchText.GetEntry(i);
917 aCurrentSettings.sSingleSearchField = m_lbField.GetSelectEntry();
918 aCurrentSettings.bAllFields = m_rbAllFields.IsChecked();
919 aCurrentSettings.nPosition = m_pSearchEngine->GetPosition();
920 aCurrentSettings.bUseFormatter = m_pSearchEngine->GetFormatterUsing();
921 aCurrentSettings.setCaseSensitive ( m_pSearchEngine->GetCaseSensitive() );
922 aCurrentSettings.bBackwards = !m_pSearchEngine->GetDirection();
923 aCurrentSettings.bWildcard = m_pSearchEngine->GetWildcard();
924 aCurrentSettings.bRegular = m_pSearchEngine->GetRegular();
925 aCurrentSettings.bApproxSearch = m_pSearchEngine->GetLevenshtein();
926 aCurrentSettings.bLevRelaxed = m_pSearchEngine->GetLevRelaxed();
927 aCurrentSettings.nLevOther = m_pSearchEngine->GetLevOther();
928 aCurrentSettings.nLevShorter = m_pSearchEngine->GetLevShorter();
929 aCurrentSettings.nLevLonger = m_pSearchEngine->GetLevLonger();
931 aCurrentSettings.bSoundsLikeCJK = m_pSearchEngine->GetTransliteration();
932 aCurrentSettings.setTransliterationFlags ( m_pSearchEngine->GetTransliterationFlags() );
934 if (m_rbSearchForNull.IsChecked())
935 aCurrentSettings.nSearchForType = 1;
936 else if (m_rbSearchForNotNull.IsChecked())
937 aCurrentSettings.nSearchForType = 2;
938 else
939 aCurrentSettings.nSearchForType = 0;
941 m_pConfig->setParams( aCurrentSettings );
944 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */