1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
)
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
)
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();
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
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
);
158 Init(fmscInitial
.strUsedFields
, sInitialText
);
161 FmSearchDialog::~FmSearchDialog()
166 void FmSearchDialog::dispose()
168 if (m_aDelayedPaint
.IsActive())
169 m_aDelayedPaint
.Stop();
176 delete m_pSearchEngine
;
177 m_pSearchEngine
= NULL
;
179 m_prbSearchForText
.clear();
180 m_prbSearchForNull
.clear();
181 m_prbSearchForNotNull
.clear();
182 m_pcmbSearchText
.clear();
185 m_prbAllFields
.clear();
186 m_prbSingleField
.clear();
188 m_pftPosition
.clear();
189 m_plbPosition
.clear();
190 m_pcbUseFormat
.clear();
192 m_pcbBackwards
.clear();
193 m_pcbStartOver
.clear();
194 m_pcbWildCard
.clear();
195 m_pcbRegular
.clear();
197 m_ppbApproxSettings
.clear();
198 m_pHalfFullFormsCJK
.clear();
199 m_pSoundsLikeCJK
.clear();
200 m_pSoundsLikeCJKSettings
.clear();
203 m_pbSearchAgain
.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
,
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
);
254 for (sal_Int32 i
=0; i
< comphelper::string::getTokenCount(strVisibleFields
, ';'); ++i
)
255 m_plbField
->InsertEntry(strVisibleFields
.getToken(i
, ';'));
258 m_pConfig
= new FmSearchConfigItem
;
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
);
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())
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);
298 // en- or disable field list box accordingly
299 if (pButton
== m_prbSingleField
)
301 m_plbField
->Enable();
302 m_pSearchEngine
->RebuildUsedFields(m_plbField
->GetSelectEntryPos());
306 m_plbField
->Disable();
307 m_pSearchEngine
->RebuildUsedFields(-1);
313 IMPL_LINK_NOARG(FmSearchDialog
, OnClickedSearchAgain
)
315 if (m_pbClose
->IsEnabled())
316 { // the button has the function 'search'
317 OUString strThisRoundText
= m_pcmbSearchText
->GetText();
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
);
337 m_pSearchEngine
->StartOverSpecial(m_prbSearchForNull
->IsChecked());
341 EnableSearchUI(false);
342 if (m_prbSearchForText
->IsChecked())
343 m_pSearchEngine
->SearchNext(strThisRoundText
);
345 m_pSearchEngine
->SearchNextSpecial(m_prbSearchForNull
->IsChecked());
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
358 IMPL_LINK(FmSearchDialog
, OnClickedSpecialSettings
, Button
*, pButton
)
360 if (m_ppbApproxSettings
== pButton
)
362 boost::scoped_ptr
<AbstractSvxSearchSimilarityDialog
> pDlg
;
364 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
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();
384 boost::scoped_ptr
<AbstractSvxJSearchOptionsDialog
> aDlg(pFact
->CreateSvxJSearchOptionsDialog( this, aSet
, m_pSearchEngine
->GetTransliterationFlags() ));
385 DBG_ASSERT(aDlg
, "Dialog creation failed!");
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
);
402 IMPL_LINK_NOARG(FmSearchDialog
, OnSearchTextModified
)
404 if ((!m_pcmbSearchText
->GetText().isEmpty()) || !m_prbSearchForText
->IsChecked())
405 m_pbSearchAgain
->Enable();
407 m_pbSearchAgain
->Disable();
409 m_pSearchEngine
->InvalidatePreviousLoc();
413 IMPL_LINK(FmSearchDialog
, OnFocusGrabbed
, ComboBox
*,)
415 m_pcmbSearchText
->SetSelection( Selection( SELECTION_MIN
, SELECTION_MAX
) );
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());
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());
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
)
466 pBoxes
[i
]->Disable();
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
)
483 m_pftPosition
->Disable();
484 m_plbPosition
->Disable();
488 m_pftPosition
->Enable();
489 m_plbPosition
->Enable();
493 // and the button for similarity-search
494 if (pBox
== m_pcbApprox
)
497 m_ppbApproxSettings
->Enable();
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
);
526 void FmSearchDialog::InitContext(sal_Int16 nContext
)
528 FmSearchContext fmscContext
;
529 fmscContext
.nContext
= nContext
;
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
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
, ';'));
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
]);
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());
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
582 EnableControlPaint(false);
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)
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
;
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
);
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 );
629 m_aDelayedPaint
.Start();
631 EnableControlPaint(true);
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
};
680 for (sal_uInt32 i
=0; i
<SAL_N_ELEMENTS(pAffectedControls
); ++i
)
682 pAffectedControls
[i
]->SetUpdateMode(bEnable
);
683 pAffectedControls
[i
]->EnablePaint(bEnable
);
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
;
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();
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();
744 case FmSearchProgress::STATE_SUCCESSFULL
:
745 OnFound(pProgress
->aBookmark
, (sal_Int16
)pProgress
->nFieldIndex
);
746 EnableSearchUI(true);
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();
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
);
771 m_pftRecord
->SetText(OUString::number(1 + pProgress
->nCurrentRecord
));
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
789 sal_Int32 nInitialField
= m_plbField
->GetEntryPos( OUString( aParams
.sSingleSearchField
) );
790 if (nInitialField
== LISTBOX_ENTRY_NOTFOUND
)
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
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
;
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
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;
901 aCurrentSettings
.nSearchForType
= 0;
903 m_pConfig
->setParams( aCurrentSettings
);
906 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */