1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cuifmsearch.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #ifdef SVX_DLLIMPLEMENTATION
35 #undef SVX_DLLIMPLEMENTATION
38 #ifndef _SVX_FMRESIDS_HRC
39 #include "fmresids.hrc"
40 #endif // _SVX_FMRESIDS_HRC
41 #include <tools/debug.hxx>
42 #include <vcl/msgbox.hxx>
45 #include <vcl/svapp.hxx>
46 #include <tools/shl.hxx>
47 #include <svx/dialmgr.hxx>
49 #include <sfx2/tabdlg.hxx> //add by CHINA001 for SfxItemSet
50 #include <osl/mutex.hxx>
51 #include <sfx2/app.hxx>
52 #ifndef _SVX_DIALOGS_HRC
53 #include <svx/dialogs.hrc>
55 #include <svtools/filerec.hxx>
56 #include "fmsrcimp.hxx"
57 #include "fmsrccfg.hxx"
60 #include "fmsearch.hrc"
61 #endif // _FMSEARCH_HRC
62 #include "cuifmsearch.hxx"
63 #include "srchdlg.hxx"
64 #include <svtools/cjkoptions.hxx>
65 #include <com/sun/star/i18n/TransliterationModules.hpp>
66 #include <comphelper/processfactory.hxx>
68 #include <svx/svxdlg.hxx> //CHINA001
70 using namespace ::com::sun::star::uno
;
71 using namespace ::com::sun::star::i18n
;
72 using namespace ::svxform
;
73 using namespace ::com::sun::star::sdbc
;
74 using namespace ::com::sun::star::util
;
76 #define MAX_HISTORY_ENTRIES 50
78 //------------------------------------------------------------------------
79 void FmSearchDialog::initCommon( const Reference
< XResultSet
>& _rxCursor
)
82 DBG_ASSERT( m_pSearchEngine
, "FmSearchDialog::initCommon: have no engine!" );
83 m_pSearchEngine
->SetProgressHandler(LINK(this, FmSearchDialog
, OnSearchProgress
));
85 // some layout changes according to available CJK options
86 SvtCJKOptions aCJKOptions
;
87 if (!aCJKOptions
.IsJapaneseFindEnabled())
89 sal_Int32 nUpper
= m_cbApprox
.GetPosPixel().Y();
90 sal_Int32 nDifference
= m_aSoundsLikeCJKSettings
.GetPosPixel().Y() - nUpper
;
92 // hide the options for the japanese search
93 Control
* pFieldsToMove
[] = { &m_flState
, &m_ftRecordLabel
, &m_ftRecord
, &m_ftHint
};
94 implMoveControls(pFieldsToMove
, sizeof(pFieldsToMove
)/sizeof(pFieldsToMove
[0]), nDifference
, &m_flOptions
);
96 m_aSoundsLikeCJK
.Hide();
97 m_aSoundsLikeCJKSettings
.Hide();
100 if (!aCJKOptions
.IsCJKFontEnabled())
102 m_aHalfFullFormsCJK
.Hide();
104 // never ignore the width (ignoring is expensive) if the option is not available at all
105 // 04.12.2001 - 91973 - fs@openoffice.org
106 m_pSearchEngine
->SetIgnoreWidthCJK( sal_False
);
109 // some initial record texts
110 m_ftRecord
.SetText( String::CreateFromInt32( _rxCursor
->getRow() ) );
111 m_pbClose
.SetHelpText(String());
114 //------------------------------------------------------------------------
115 FmSearchDialog::FmSearchDialog(Window
* pParent
, const UniString
& sInitialText
, const ::std::vector
< String
>& _rContexts
, sal_Int16 nInitialContext
,
116 const Link
& lnkContextSupplier
)
117 :ModalDialog(pParent
, SVX_RES(RID_SVXDLG_SEARCHFORM
))
118 ,m_flSearchFor (this, SVX_RES(FL_SEARCHFOR
))
119 ,m_rbSearchForText (this, SVX_RES(RB_SEARCHFORTEXT
))
120 ,m_rbSearchForNull (this, SVX_RES(RB_SEARCHFORNULL
))
121 ,m_rbSearchForNotNull (this, SVX_RES(RB_SEARCHFORNOTNULL
))
122 ,m_cmbSearchText (this, SVX_RES(CMB_SEARCHTEXT
))
123 ,m_flWhere (this, SVX_RES(FL_WHERE
))
124 ,m_ftForm (this, SVX_RES(FT_FORM
))
125 ,m_lbForm (this, SVX_RES(LB_FORM
))
126 ,m_rbAllFields (this, SVX_RES(RB_ALLFIELDS
))
127 ,m_rbSingleField (this, SVX_RES(RB_SINGLEFIELD
))
128 ,m_lbField (this, SVX_RES(LB_FIELD
))
129 ,m_flOptions (this, SVX_RES(FL_OPTIONS
))
130 ,m_ftPosition (this, SVX_RES(FT_POSITION
))
131 ,m_lbPosition (this, SVX_RES(LB_POSITION
))
132 ,m_cbUseFormat (this, SVX_RES(CB_USEFORMATTER
))
133 ,m_cbCase (this, SVX_RES(CB_CASE
))
134 ,m_cbBackwards (this, SVX_RES(CB_BACKWARD
))
135 ,m_cbStartOver (this, SVX_RES(CB_STARTOVER
))
136 ,m_cbWildCard (this, SVX_RES(CB_WILDCARD
))
137 ,m_cbRegular (this, SVX_RES(CB_REGULAR
))
138 ,m_cbApprox (this, SVX_RES(CB_APPROX
))
139 ,m_pbApproxSettings (this, SVX_RES(PB_APPROXSETTINGS
))
140 ,m_aHalfFullFormsCJK (this, SVX_RES(CB_HALFFULLFORMS
))
141 ,m_aSoundsLikeCJK (this, SVX_RES(CB_SOUNDSLIKECJK
))
142 ,m_aSoundsLikeCJKSettings (this, SVX_RES(PB_SOUNDSLIKESETTINGS
))
143 ,m_flState (this, SVX_RES(FL_STATE
))
144 ,m_ftRecordLabel (this, SVX_RES(FT_RECORDLABEL
))
145 ,m_ftRecord (this, SVX_RES(FT_RECORD
))
146 ,m_ftHint (this, SVX_RES(FT_HINT
))
147 ,m_pbSearchAgain (this, SVX_RES(PB_SEARCH
))
148 ,m_pbClose (this, SVX_RES(1))
149 ,m_pbHelp (this, SVX_RES(1))
150 ,m_sSearch ( m_pbSearchAgain
.GetText() )
151 ,m_sCancel ( Button::GetStandardText( BUTTON_CANCEL
) )
152 ,m_pPreSearchFocus( NULL
)
153 ,m_lnkContextSupplier(lnkContextSupplier
)
156 DBG_ASSERT(m_lnkContextSupplier
.IsSet(), "FmSearchDialog::FmSearchDialog : have no ContextSupplier !");
158 // erst mal die Informationen fuer den initialen Kontext
159 FmSearchContext fmscInitial
;
160 fmscInitial
.nContext
= nInitialContext
;
161 m_lnkContextSupplier
.Call(&fmscInitial
);
162 DBG_ASSERT(fmscInitial
.xCursor
.is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
163 DBG_ASSERT(fmscInitial
.strUsedFields
.GetTokenCount(';') == (xub_StrLen
)fmscInitial
.arrFields
.size(),
164 "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplied !");
165 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
166 for (sal_Int32 i
=0; i
<(sal_Int32
)fmscInitial
.arrFields
.size(); ++i
)
167 DBG_ASSERT(fmscInitial
.arrFields
.at(i
).is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
168 #endif // (OSL_DEBUG_LEVEL > 1) || DBG_UTIL
170 for ( ::std::vector
< String
>::const_iterator context
= _rContexts
.begin();
171 context
!= _rContexts
.end();
175 m_arrContextFields
.push_back(String());
176 m_lbForm
.InsertEntry(*context
);
178 m_lbForm
.SelectEntryPos(nInitialContext
);
180 m_lbForm
.SetSelectHdl(LINK(this, FmSearchDialog
, OnContextSelection
));
182 if (m_arrContextFields
.size() == 1)
183 { // remove the context selection listbox and rearrange the controls accordingly
184 sal_Int32 nUpper
= m_lbForm
.GetPosPixel().Y();
185 sal_Int32 nDifference
= m_rbAllFields
.GetPosPixel().Y() - nUpper
;
187 // move all controls below the affected ones up
188 Control
* pFieldsToMove
[] = { &m_rbAllFields
, &m_rbSingleField
, &m_lbField
, &m_flOptions
, &m_ftPosition
, &m_lbPosition
,
189 &m_cbUseFormat
, &m_cbCase
, &m_cbBackwards
, &m_cbStartOver
, &m_cbWildCard
, &m_cbRegular
, &m_cbApprox
,
190 &m_pbApproxSettings
, &m_aHalfFullFormsCJK
, &m_aSoundsLikeCJK
, &m_aSoundsLikeCJKSettings
,
191 &m_flState
, &m_ftRecordLabel
, &m_ftRecord
, &m_ftHint
};
193 implMoveControls(pFieldsToMove
, sizeof(pFieldsToMove
)/sizeof(pFieldsToMove
[0]), nDifference
, &m_flWhere
);
195 Point pt
= m_rbAllFields
.GetPosPixel();
196 pt
.X() = m_ftForm
.GetPosPixel().X();
197 m_rbAllFields
.SetPosPixel( pt
);
198 pt
= m_rbSingleField
.GetPosPixel();
199 pt
.X() = m_ftForm
.GetPosPixel().X();
200 m_rbSingleField
.SetPosPixel( pt
);
202 // hide dispensable controls
207 m_pSearchEngine
= new FmSearchEngine(
208 ::comphelper::getProcessServiceFactory(), fmscInitial
.xCursor
, fmscInitial
.strUsedFields
, fmscInitial
.arrFields
, SM_ALLOWSCHEDULE
);
209 initCommon( fmscInitial
.xCursor
);
211 if (fmscInitial
.sFieldDisplayNames
.Len() != 0)
212 { // use the display names if supplied
213 DBG_ASSERT(fmscInitial
.sFieldDisplayNames
.GetTokenCount() == fmscInitial
.strUsedFields
.GetTokenCount(),
214 "FmSearchDialog::FmSearchDialog : invalid initial context description !");
215 Init(fmscInitial
.sFieldDisplayNames
, sInitialText
);
218 Init(fmscInitial
.strUsedFields
, sInitialText
);
221 //------------------------------------------------------------------------
222 void FmSearchDialog::implMoveControls(
223 Control
** _ppControls
,
224 sal_Int32 _nControls
,
226 Control
* /*_pToResize*/)
228 for (sal_Int32 i
=0; i
<_nControls
; ++i
)
230 Point pt
= _ppControls
[i
]->GetPosPixel();
232 _ppControls
[i
]->SetPosPixel(pt
);
236 Size sz
= GetSizePixel();
241 //------------------------------------------------------------------------
242 FmSearchDialog::~FmSearchDialog()
244 if (m_aDelayedPaint
.IsActive())
245 m_aDelayedPaint
.Stop();
255 delete m_pSearchEngine
;
258 //------------------------------------------------------------------------
259 void FmSearchDialog::Init(const UniString
& strVisibleFields
, const UniString
& sInitialText
)
261 // die Initialisierung all der Controls
262 m_rbSearchForText
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedFieldRadios
));
263 m_rbSearchForNull
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedFieldRadios
));
264 m_rbSearchForNotNull
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedFieldRadios
));
266 m_rbAllFields
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedFieldRadios
));
267 m_rbSingleField
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedFieldRadios
));
269 m_pbSearchAgain
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedSearchAgain
));
270 m_pbApproxSettings
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedSpecialSettings
));
271 m_aSoundsLikeCJKSettings
.SetClickHdl(LINK(this, FmSearchDialog
, OnClickedSpecialSettings
));
273 m_lbPosition
.SetSelectHdl(LINK(this, FmSearchDialog
, OnPositionSelected
));
274 m_lbField
.SetSelectHdl(LINK(this, FmSearchDialog
, OnFieldSelected
));
276 m_cmbSearchText
.SetModifyHdl(LINK(this, FmSearchDialog
, OnSearchTextModified
));
277 m_cmbSearchText
.EnableAutocomplete(sal_False
);
279 m_cbUseFormat
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
280 m_cbBackwards
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
281 m_cbStartOver
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
282 m_cbCase
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
283 m_cbWildCard
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
284 m_cbRegular
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
285 m_cbApprox
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
286 m_aHalfFullFormsCJK
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
287 m_aSoundsLikeCJK
.SetToggleHdl(LINK(this, FmSearchDialog
, OnCheckBoxToggled
));
289 // die Listboxen fuellen
290 // die Methoden des Feldvergleiches
292 RID_STR_SEARCH_ANYWHERE
,
293 RID_STR_SEARCH_BEGINNING
,
297 for ( size_t i
=0; i
<sizeof(nResIds
)/sizeof(nResIds
[0]); ++i
)
298 m_lbPosition
.InsertEntry( String( SVX_RES( nResIds
[i
] ) ) );
299 m_lbPosition
.SelectEntryPos(MATCHING_ANYWHERE
);
302 for (USHORT i
=0; i
<strVisibleFields
.GetTokenCount(';'); ++i
)
303 m_lbField
.InsertEntry(strVisibleFields
.GetToken(i
, ';'));
306 m_pConfig
= new FmSearchConfigItem
;
309 m_cmbSearchText
.SetText(sInitialText
);
310 // wenn die Edit-Zeile den Text veraendert hat (weil er zum Beispiel Steuerzeichen enthielt, wie das bei Memofeldern der Fall
311 // sein kann), nehme ich einen leeren UniString
312 UniString sRealSetText
= m_cmbSearchText
.GetText();
313 if (!sRealSetText
.Equals(sInitialText
))
314 m_cmbSearchText
.SetText(UniString());
315 LINK(this, FmSearchDialog
, OnSearchTextModified
).Call(&m_cmbSearchText
);
317 // initial die ganzen UI-Elemente fuer die Suche an
318 m_aDelayedPaint
.SetTimeoutHdl(LINK(this, FmSearchDialog
, OnDelayedPaint
));
319 m_aDelayedPaint
.SetTimeout(500);
320 EnableSearchUI(sal_True
);
322 if ( m_rbSearchForText
.IsChecked() )
323 m_cmbSearchText
.GrabFocus();
328 //------------------------------------------------------------------------
329 sal_Bool
FmSearchDialog::Close()
331 // Wenn der Close-Button disabled ist und man im Dialog ESC drueckt, dann wird irgendwo vom Frame trotzdem Close aufgerufen,
332 // was ich allerdings nicht will, wenn ich gerade mitten in einer (eventuell in einem extra Thread laufenden) Suche bin
333 if (!m_pbClose
.IsEnabled())
335 return ModalDialog::Close();
338 //------------------------------------------------------------------------
339 IMPL_LINK(FmSearchDialog
, OnClickedFieldRadios
, Button
*, pButton
)
341 if ((pButton
== &m_rbSearchForText
) || (pButton
== &m_rbSearchForNull
) || (pButton
== &m_rbSearchForNotNull
))
343 EnableSearchForDependees(sal_True
);
346 // die Feldlistbox entsprechend en- oder disablen
347 if (pButton
== &m_rbSingleField
)
350 m_pSearchEngine
->RebuildUsedFields(m_lbField
.GetSelectEntryPos());
355 m_pSearchEngine
->RebuildUsedFields(-1);
361 //------------------------------------------------------------------------
362 IMPL_LINK(FmSearchDialog
, OnClickedSearchAgain
, Button
*, EMPTYARG
)
364 if (m_pbClose
.IsEnabled())
365 { // der Button hat die Funktion 'Suchen'
366 UniString strThisRoundText
= m_cmbSearchText
.GetText();
368 m_cmbSearchText
.RemoveEntry(strThisRoundText
);
369 m_cmbSearchText
.InsertEntry(strThisRoundText
, 0);
370 // das Remove/Insert stellt a) sicher, dass der UniString nicht zweimal auftaucht, b), dass die zuletzt gesuchten Strings am
372 // und die Listenlaenge beschraenken
373 while (m_cmbSearchText
.GetEntryCount() > MAX_HISTORY_ENTRIES
)
374 m_cmbSearchText
.RemoveEntry(m_cmbSearchText
.GetEntryCount()-1);
376 // den 'Ueberlauf'-Hint rausnehmen
377 m_ftHint
.SetText(UniString());
378 m_ftHint
.Invalidate();
380 if (m_cbStartOver
.IsChecked())
382 m_cbStartOver
.Check(sal_False
);
383 EnableSearchUI(sal_False
);
384 if (m_rbSearchForText
.IsChecked())
385 m_pSearchEngine
->StartOver(strThisRoundText
);
387 m_pSearchEngine
->StartOverSpecial(m_rbSearchForNull
.IsChecked());
391 EnableSearchUI(sal_False
);
392 if (m_rbSearchForText
.IsChecked())
393 m_pSearchEngine
->SearchNext(strThisRoundText
);
395 m_pSearchEngine
->SearchNextSpecial(m_rbSearchForNull
.IsChecked());
399 { // der Button hat die Fukntion 'Abbrechen'
400 DBG_ASSERT(m_pSearchEngine
->GetSearchMode() != SM_BRUTE
, "FmSearchDialog, OnClickedSearchAgain : falscher Modus !");
401 // der CancelButton wird normalerweise nur disabled, wenn ich in einem Thread oder mit Reschedule arbeite
402 m_pSearchEngine
->CancelSearch();
403 // mein ProgressHandler wird gerufen, wenn es wirklich zu Ende ist, das hier war nur eine Anforderung
408 //------------------------------------------------------------------------
409 IMPL_LINK(FmSearchDialog
, OnClickedSpecialSettings
, Button
*, pButton
)
411 if (&m_pbApproxSettings
== pButton
)
413 AbstractSvxSearchSimilarityDialog
* pDlg
= NULL
;
415 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
417 pDlg
= pFact
->CreateSvxSearchSimilarityDialog( this, m_pSearchEngine
->GetLevRelaxed(), m_pSearchEngine
->GetLevOther(),
418 m_pSearchEngine
->GetLevShorter(), m_pSearchEngine
->GetLevLonger() );
419 DBG_ASSERT( pDlg
, "FmSearchDialog, OnClickedSpecialSettings: could not load the dialog!" );
421 if ( pDlg
&& pDlg
->Execute() == RET_OK
)
423 m_pSearchEngine
->SetLevRelaxed( pDlg
->IsRelaxed() );
424 m_pSearchEngine
->SetLevOther( pDlg
->GetOther() );
425 m_pSearchEngine
->SetLevShorter(pDlg
->GetShorter() );
426 m_pSearchEngine
->SetLevLonger( pDlg
->GetLonger() );
430 else if (&m_aSoundsLikeCJKSettings
== pButton
)
432 SfxItemSet
aSet( SFX_APP()->GetPool() );
433 //CHINA001 SvxJSearchOptionsDialog aDlg( this, aSet, RID_SVXPAGE_JSEARCH_OPTIONS, m_pSearchEngine->GetTransliterationFlags() );
434 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
437 AbstractSvxJSearchOptionsDialog
* aDlg
= pFact
->CreateSvxJSearchOptionsDialog( this, aSet
, RID_SVXPAGE_JSEARCH_OPTIONS
, m_pSearchEngine
->GetTransliterationFlags(), RID_SVXPAGE_JSEARCH_OPTIONS
);
438 DBG_ASSERT(aDlg
, "Dialogdiet fail!");//CHINA001
439 aDlg
->Execute(); //CHINA001 aDlg.Execute();
442 INT32 nFlags
= aDlg
->GetTransliterationFlags(); //CHINA001 INT32 nFlags = aDlg.GetTransliterationFlags();
443 m_pSearchEngine
->SetTransliterationFlags(nFlags
);
445 m_cbCase
.Check(m_pSearchEngine
->GetCaseSensitive());
446 OnCheckBoxToggled( &m_cbCase
);
447 m_aHalfFullFormsCJK
.Check( !m_pSearchEngine
->GetIgnoreWidthCJK() );
448 OnCheckBoxToggled( &m_aHalfFullFormsCJK
);
449 delete aDlg
; //add for CHINA001
456 //------------------------------------------------------------------------
457 IMPL_LINK(FmSearchDialog
, OnSearchTextModified
, ComboBox
*, EMPTYARG
)
459 if ((m_cmbSearchText
.GetText().Len() != 0) || !m_rbSearchForText
.IsChecked())
460 m_pbSearchAgain
.Enable();
462 m_pbSearchAgain
.Disable();
464 m_pSearchEngine
->InvalidatePreviousLoc();
468 //------------------------------------------------------------------------
469 IMPL_LINK(FmSearchDialog
, OnPositionSelected
, ListBox
*, pBox
)
471 (void) pBox
; // avoid warning
472 DBG_ASSERT(pBox
->GetSelectEntryCount() == 1, "FmSearchDialog::OnMethodSelected : unerwartet : nicht genau ein Eintrag selektiert !");
474 m_pSearchEngine
->SetPosition(m_lbPosition
.GetSelectEntryPos());
478 //------------------------------------------------------------------------
479 IMPL_LINK(FmSearchDialog
, OnFieldSelected
, ListBox
*, pBox
)
481 (void) pBox
; // avoid warning
482 DBG_ASSERT(pBox
->GetSelectEntryCount() == 1, "FmSearchDialog::OnFieldSelected : unerwartet : nicht genau ein Eintrag selektiert !");
484 m_pSearchEngine
->RebuildUsedFields(m_rbAllFields
.IsChecked() ? -1 : (sal_Int16
)m_lbField
.GetSelectEntryPos());
485 // ruft auch m_pSearchEngine->InvalidatePreviousLoc auf
487 sal_Int32 nCurrentContext
= m_lbForm
.GetSelectEntryPos();
488 if (nCurrentContext
!= LISTBOX_ENTRY_NOTFOUND
)
489 m_arrContextFields
[nCurrentContext
] = UniString(m_lbField
.GetSelectEntry());
493 //------------------------------------------------------------------------
494 IMPL_LINK(FmSearchDialog
, OnCheckBoxToggled
, CheckBox
*, pBox
)
496 sal_Bool bChecked
= pBox
->IsChecked();
498 // Formatter oder case -> an die Engine weiterreichen
499 if (pBox
== &m_cbUseFormat
)
500 m_pSearchEngine
->SetFormatterUsing(bChecked
);
501 else if (pBox
== &m_cbCase
)
502 m_pSearchEngine
->SetCaseSensitive(bChecked
);
503 // Richtung -> weiterreichen und Checkbox-Text fuer StartOver neu setzen
504 else if (pBox
== &m_cbBackwards
)
506 m_cbStartOver
.SetText( String( SVX_RES( bChecked
? RID_STR_FROM_BOTTOM
: RID_STR_FROM_TOP
) ) );
507 m_pSearchEngine
->SetDirection(!bChecked
);
509 // Aehnlichkeitssuche oder regulaerer Ausdruck
510 else if ((pBox
== &m_cbApprox
) || (pBox
== &m_cbRegular
) || (pBox
== &m_cbWildCard
))
512 // die beiden jeweils anderen Boxes disablen oder enablen
513 CheckBox
* pBoxes
[] = { &m_cbWildCard
, &m_cbRegular
, &m_cbApprox
};
514 for (sal_uInt32 i
=0; i
<sizeof(pBoxes
)/sizeof(CheckBox
*); ++i
)
516 if (pBoxes
[i
] != pBox
)
519 pBoxes
[i
]->Disable();
525 // an die Engine weiterreichen
526 m_pSearchEngine
->SetWildcard(m_cbWildCard
.IsEnabled() ? m_cbWildCard
.IsChecked() : sal_False
);
527 m_pSearchEngine
->SetRegular(m_cbRegular
.IsEnabled() ? m_cbRegular
.IsChecked() : sal_False
);
528 m_pSearchEngine
->SetLevenshtein(m_cbApprox
.IsEnabled() ? m_cbApprox
.IsChecked() : sal_False
);
529 // (Boxes, die disabled sind, muessen als sal_False an die Engine gehen)
531 // die Position-Listbox anpassen (ist bei Wildcard-Suche nicht erlaubt)
532 if (pBox
== &m_cbWildCard
)
536 m_ftPosition
.Disable();
537 m_lbPosition
.Disable();
541 m_ftPosition
.Enable();
542 m_lbPosition
.Enable();
546 // und den Button fuer die Aehnlichkeitssuche
547 if (pBox
== &m_cbApprox
)
550 m_pbApproxSettings
.Enable();
552 m_pbApproxSettings
.Disable();
555 else if (pBox
== &m_aHalfFullFormsCJK
)
557 // forward to the search engine
558 m_pSearchEngine
->SetIgnoreWidthCJK( !bChecked
);
560 else if (pBox
== &m_aSoundsLikeCJK
)
562 m_aSoundsLikeCJKSettings
.Enable(bChecked
);
564 // two other buttons which depend on this one
565 sal_Bool bEnable
= ( m_rbSearchForText
.IsChecked()
566 && !m_aSoundsLikeCJK
.IsChecked()
568 || !SvtCJKOptions().IsJapaneseFindEnabled();
569 m_cbCase
.Enable(bEnable
);
570 m_aHalfFullFormsCJK
.Enable(bEnable
);
572 // forward to the search engine
573 m_pSearchEngine
->SetTransliteration( bChecked
);
579 //------------------------------------------------------------------------
580 void FmSearchDialog::InitContext(sal_Int16 nContext
)
582 FmSearchContext fmscContext
;
583 fmscContext
.nContext
= nContext
;
588 m_lnkContextSupplier
.Call(&fmscContext
);
589 DBG_ASSERT(nResult
> 0, "FmSearchDialog::InitContext : ContextSupplier didn't give me any controls !");
591 // packen wir zuerst die Feld-Namen in die entsprechende Listbox
594 if (fmscContext
.sFieldDisplayNames
.Len() != 0)
596 // use the display names if supplied
597 DBG_ASSERT(fmscContext
.sFieldDisplayNames
.GetTokenCount() == fmscContext
.strUsedFields
.GetTokenCount(),
598 "FmSearchDialog::InitContext : invalid context description supplied !");
599 for (xub_StrLen i
=0; i
<fmscContext
.sFieldDisplayNames
.GetTokenCount(); ++i
)
600 m_lbField
.InsertEntry(fmscContext
.sFieldDisplayNames
.GetToken(i
));
603 // else use the field names
604 for (xub_StrLen i
=0; i
<fmscContext
.strUsedFields
.GetTokenCount(); ++i
)
605 m_lbField
.InsertEntry(fmscContext
.strUsedFields
.GetToken(i
));
607 if (nContext
< (sal_Int32
)m_arrContextFields
.size() && m_arrContextFields
[nContext
].Len())
609 m_lbField
.SelectEntry(m_arrContextFields
[nContext
]);
613 m_lbField
.SelectEntryPos(0);
614 if (m_rbSingleField
.IsChecked() && (m_lbField
.GetEntryCount() > 1))
615 m_lbField
.GrabFocus();
618 // dann geben wir der Engine Bescheid
619 m_pSearchEngine
->SwitchToContext(fmscContext
.xCursor
, fmscContext
.strUsedFields
, fmscContext
.arrFields
,
620 m_rbAllFields
.IsChecked() ? -1 : 0);
622 // und die Position des neuen Cursors anzeigen
623 m_ftRecord
.SetText(String::CreateFromInt32(fmscContext
.xCursor
->getRow()));
626 //------------------------------------------------------------------------
627 IMPL_LINK( FmSearchDialog
, OnContextSelection
, ListBox
*, pBox
)
629 InitContext(pBox
->GetSelectEntryPos());
633 //------------------------------------------------------------------------
634 void FmSearchDialog::EnableSearchUI(sal_Bool bEnable
)
636 // wenn die Controls disabled werden sollen, schalte ich mal eben kurz ihr Paint aus und verzoegert wieder an
638 EnableControlPaint(sal_False
);
640 { // beim Enablen teste ich, ob der Timer fuer das delayed paint aktiv ist und stoppe ihn wenn noetig
641 if (m_aDelayedPaint
.IsActive())
642 m_aDelayedPaint
.Stop();
644 // (das ganze geht unten noch weiter)
645 // diese kleine Verrenkung fuehrt hoffentlich dazu, dass es nicht flackert, wenn man die SearchUI schnell hintereinander
646 // aus- und wieder einschaltet (wie das bei einem kurzen Suchvorgang zwangslaeufig der Fall ist)
650 // if one of my children has the focus, remember it
651 // 104332 - 2002-10-17 - fs@openoffice.org
652 Window
* pFocusWindow
= Application::GetFocusWindow( );
653 if ( pFocusWindow
&& IsChild( pFocusWindow
) )
654 m_pPreSearchFocus
= pFocusWindow
;
656 m_pPreSearchFocus
= NULL
;
659 // der Suchen-Button hat einen Doppelfunktion, seinen Text entsprechend anpassen
660 String
sButtonText( bEnable
? m_sSearch
: m_sCancel
);
661 m_pbSearchAgain
.SetText( sButtonText
);
663 // jetzt Controls en- oder disablen
664 if (m_pSearchEngine
->GetSearchMode() != SM_BRUTE
)
666 m_flSearchFor
.Enable (bEnable
);
667 m_rbSearchForText
.Enable (bEnable
);
668 m_rbSearchForNull
.Enable (bEnable
);
669 m_rbSearchForNotNull
.Enable (bEnable
);
670 m_flWhere
.Enable (bEnable
);
671 m_ftForm
.Enable (bEnable
);
672 m_lbForm
.Enable (bEnable
);
673 m_rbAllFields
.Enable (bEnable
);
674 m_rbSingleField
.Enable (bEnable
);
675 m_lbField
.Enable (bEnable
&& m_rbSingleField
.IsChecked());
676 m_flOptions
.Enable (bEnable
);
677 m_cbBackwards
.Enable (bEnable
);
678 m_cbStartOver
.Enable (bEnable
);
679 m_pbClose
.Enable (bEnable
);
680 EnableSearchForDependees (bEnable
);
683 { // this means we're preparing for starting a search
684 // In this case, EnableSearchForDependees disabled the search button
685 // But as we're about to use it for cancelling the search, we really need to enable it, again
686 // 07.12.2001 - 95246 - fs@openoffice.org
687 m_pbSearchAgain
.Enable( sal_True
);
691 // und den Rest fuer das delayed paint
693 m_aDelayedPaint
.Start();
695 EnableControlPaint(sal_True
);
699 // 104332 - 2002-10-17 - fs@openoffice.org
700 if ( m_pPreSearchFocus
)
702 m_pPreSearchFocus
->GrabFocus();
703 if ( WINDOW_EDIT
== m_pPreSearchFocus
->GetType() )
705 Edit
* pEdit
= static_cast< Edit
* >( m_pPreSearchFocus
);
706 pEdit
->SetSelection( Selection( 0, pEdit
->GetText().Len() ) );
709 m_pPreSearchFocus
= NULL
;
714 //------------------------------------------------------------------------
715 void FmSearchDialog::EnableSearchForDependees(sal_Bool bEnable
)
717 sal_Bool bSearchingForText
= m_rbSearchForText
.IsChecked();
718 m_pbSearchAgain
.Enable(bEnable
&& (!bSearchingForText
|| (m_cmbSearchText
.GetText().Len() != 0)));
720 bEnable
= bEnable
&& bSearchingForText
;
722 sal_Bool bEnableRedundants
= !m_aSoundsLikeCJK
.IsChecked() || !SvtCJKOptions().IsJapaneseFindEnabled();
724 m_cmbSearchText
.Enable (bEnable
);
725 m_ftPosition
.Enable (bEnable
&& !m_cbWildCard
.IsChecked());
726 m_cbWildCard
.Enable (bEnable
&& !m_cbRegular
.IsChecked() && !m_cbApprox
.IsChecked());
727 m_cbRegular
.Enable (bEnable
&& !m_cbWildCard
.IsChecked() && !m_cbApprox
.IsChecked());
728 m_cbApprox
.Enable (bEnable
&& !m_cbWildCard
.IsChecked() && !m_cbRegular
.IsChecked());
729 m_pbApproxSettings
.Enable (bEnable
&& m_cbApprox
.IsChecked());
730 m_aHalfFullFormsCJK
.Enable (bEnable
&& bEnableRedundants
);
731 m_aSoundsLikeCJK
.Enable (bEnable
);
732 m_aSoundsLikeCJKSettings
.Enable (bEnable
&& m_aSoundsLikeCJK
.IsChecked());
733 m_lbPosition
.Enable (bEnable
&& !m_cbWildCard
.IsChecked());
734 m_cbUseFormat
.Enable (bEnable
);
735 m_cbCase
.Enable (bEnable
&& bEnableRedundants
);
738 //------------------------------------------------------------------------
739 void FmSearchDialog::EnableControlPaint(sal_Bool bEnable
)
741 Control
* pAffectedControls
[] = { &m_flSearchFor
, &m_rbSearchForText
, &m_cmbSearchText
, &m_rbSearchForNull
, &m_rbSearchForNotNull
,
742 &m_rbSearchForText
, &m_flWhere
, &m_rbAllFields
, &m_rbSingleField
, &m_lbField
, &m_flOptions
, &m_ftPosition
, &m_lbPosition
,
743 &m_cbUseFormat
, &m_cbCase
, &m_cbBackwards
, &m_cbStartOver
, &m_cbWildCard
, &m_cbRegular
, &m_cbApprox
, &m_pbApproxSettings
,
744 &m_pbSearchAgain
, &m_pbClose
};
747 for (sal_uInt32 i
=0; i
<sizeof(pAffectedControls
)/sizeof(pAffectedControls
[0]); ++i
)
749 pAffectedControls
[i
]->SetUpdateMode(bEnable
);
750 pAffectedControls
[i
]->EnablePaint(bEnable
);
753 for (sal_uInt32 i
=0; i
<sizeof(pAffectedControls
)/sizeof(pAffectedControls
[0]); ++i
)
755 pAffectedControls
[i
]->EnablePaint(bEnable
);
756 pAffectedControls
[i
]->SetUpdateMode(bEnable
);
760 //------------------------------------------------------------------------
761 IMPL_LINK(FmSearchDialog
, OnDelayedPaint
, void*, EMPTYARG
)
763 EnableControlPaint(sal_True
);
767 //------------------------------------------------------------------------
768 void FmSearchDialog::OnFound(const ::com::sun::star::uno::Any
& aCursorPos
, sal_Int16 nFieldPos
)
770 FmFoundRecordInformation friInfo
;
771 friInfo
.nContext
= m_lbForm
.GetSelectEntryPos();
772 // wenn ich keine Suche in Kontexten mache, steht hier was ungueltiges drin, aber dann ist es auch egal
773 friInfo
.aPosition
= aCursorPos
;
774 if (m_rbAllFields
.IsChecked())
775 friInfo
.nFieldPos
= nFieldPos
;
777 friInfo
.nFieldPos
= m_lbField
.GetSelectEntryPos();
778 // das setzt natuerlich voraus, dass ich wirklich in dem Feld gesucht habe, dass in der Listbox ausgewaehlt ist,
779 // genau das wird auch in RebuildUsedFields sichergestellt
781 // dem Handler Bescheid sagen
782 m_lnkFoundHandler
.Call(&friInfo
);
784 // und wieder Focus auf mich
785 m_cmbSearchText
.GrabFocus();
788 //------------------------------------------------------------------------
789 IMPL_LINK(FmSearchDialog
, OnSearchProgress
, FmSearchProgress
*, pProgress
)
791 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
792 // diese eine Methode Thread-sicher machen (das ist ein Overkill, die ganze restliche Applikation dafuer zu blockieren,
793 // aber im Augenblick haben wir kein anderes Sicherheitskonpzept)
795 switch (pProgress
->aSearchState
)
797 case FmSearchProgress::STATE_PROGRESS
:
798 if (pProgress
->bOverflow
)
800 String
sHint( SVX_RES( m_cbBackwards
.IsChecked() ? RID_STR_OVERFLOW_BACKWARD
: RID_STR_OVERFLOW_FORWARD
) );
801 m_ftHint
.SetText( sHint
);
802 m_ftHint
.Invalidate();
805 m_ftRecord
.SetText(String::CreateFromInt32(1 + pProgress
->nCurrentRecord
));
806 m_ftRecord
.Invalidate();
809 case FmSearchProgress::STATE_PROGRESS_COUNTING
:
810 m_ftHint
.SetText(SVX_RESSTR(RID_STR_SEARCH_COUNTING
));
811 m_ftHint
.Invalidate();
813 m_ftRecord
.SetText(String::CreateFromInt32(pProgress
->nCurrentRecord
));
814 m_ftRecord
.Invalidate();
817 case FmSearchProgress::STATE_SUCCESSFULL
:
818 OnFound(pProgress
->aBookmark
, (sal_Int16
)pProgress
->nFieldIndex
);
819 EnableSearchUI(sal_True
);
822 case FmSearchProgress::STATE_ERROR
:
823 case FmSearchProgress::STATE_NOTHINGFOUND
:
825 sal_uInt16 nErrorId
= (FmSearchProgress::STATE_ERROR
== pProgress
->aSearchState
)
826 ? RID_SVXERR_SEARCH_GENERAL_ERROR
827 : RID_SVXERR_SEARCH_NORECORD
;
828 ErrorBox(this, SVX_RES(nErrorId
)).Execute();
831 case FmSearchProgress::STATE_CANCELED
:
832 EnableSearchUI(sal_True
);
833 if (m_lnkCanceledNotFoundHdl
.IsSet())
835 FmFoundRecordInformation friInfo
;
836 friInfo
.nContext
= m_lbForm
.GetSelectEntryPos();
837 // wenn ich keine Suche in Kontexten mache, steht hier was ungueltiges drin, aber dann ist es auch egal
838 friInfo
.aPosition
= pProgress
->aBookmark
;
839 m_lnkCanceledNotFoundHdl
.Call(&friInfo
);
844 m_ftRecord
.SetText(String::CreateFromInt32(1 + pProgress
->nCurrentRecord
));
849 //------------------------------------------------------------------------
850 void FmSearchDialog::LoadParams()
852 FmSearchParams
aParams(m_pConfig
->getParams());
854 const ::rtl::OUString
* pHistory
= aParams
.aHistory
.getConstArray();
855 const ::rtl::OUString
* pHistoryEnd
= pHistory
+ aParams
.aHistory
.getLength();
856 for (; pHistory
!= pHistoryEnd
; ++pHistory
)
857 m_cmbSearchText
.InsertEntry( *pHistory
);
859 // die Einstellungen nehme ich an meinen UI-Elementen vor und rufe dann einfach den entsprechenden Change-Handler auf,
860 // dadurch werden die Daten an die SearchEngine weitergereicht und alle abhaengigen Enstellungen vorgenommen
863 sal_uInt16 nInitialField
= m_lbField
.GetEntryPos( String( aParams
.sSingleSearchField
) );
864 if (nInitialField
== COMBOBOX_ENTRY_NOTFOUND
)
866 m_lbField
.SelectEntryPos(nInitialField
);
867 LINK(this, FmSearchDialog
, OnFieldSelected
).Call(&m_lbField
);
868 // alle/einzelnes Feld (NACH dem Selektieren des Feldes, da OnClickedFieldRadios dort einen gueltigen Eintrag erwartet)
869 if (aParams
.bAllFields
)
871 m_rbSingleField
.Check(sal_False
);
872 m_rbAllFields
.Check(sal_True
);
873 LINK(this, FmSearchDialog
, OnClickedFieldRadios
).Call(&m_rbAllFields
);
874 // OnClickedFieldRadios ruft auch um RebuildUsedFields
878 m_rbAllFields
.Check(sal_False
);
879 m_rbSingleField
.Check(sal_True
);
880 LINK(this, FmSearchDialog
, OnClickedFieldRadios
).Call(&m_rbSingleField
);
884 m_lbPosition
.SelectEntryPos(aParams
.nPosition
);
885 LINK(this, FmSearchDialog
, OnPositionSelected
).Call(&m_lbPosition
);
887 // Feld-Formatierung/Case-Sensitivitaet/Richtung
888 m_cbUseFormat
.Check(aParams
.bUseFormatter
);
889 m_cbCase
.Check( aParams
.isCaseSensitive() );
890 m_cbBackwards
.Check(aParams
.bBackwards
);
891 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_cbUseFormat
);
892 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_cbCase
);
893 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_cbBackwards
);
895 m_aHalfFullFormsCJK
.Check( !aParams
.isIgnoreWidthCJK( ) ); // BEWARE: this checkbox has a inverse semantics!
896 m_aSoundsLikeCJK
.Check( aParams
.bSoundsLikeCJK
);
897 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_aHalfFullFormsCJK
);
898 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_aSoundsLikeCJK
);
900 // die drei Checkboxen fuer spezielle Sucharten
901 // erst mal alle ruecksetzen
902 m_cbWildCard
.Check(sal_False
);
903 m_cbRegular
.Check(sal_False
);
904 m_cbApprox
.Check(sal_False
);
905 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_cbWildCard
);
906 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_cbRegular
);
907 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(&m_cbApprox
);
909 // dann die richtige setzen
910 CheckBox
* pToCheck
= NULL
;
911 if (aParams
.bWildcard
)
912 pToCheck
= &m_cbWildCard
;
913 if (aParams
.bRegular
)
914 pToCheck
= &m_cbRegular
;
915 if (aParams
.bApproxSearch
)
916 pToCheck
= &m_cbApprox
;
917 if (aParams
.bSoundsLikeCJK
)
918 pToCheck
= &m_aSoundsLikeCJK
;
921 pToCheck
->Check(sal_True
);
922 LINK(this, FmSearchDialog
, OnCheckBoxToggled
).Call(pToCheck
);
925 // die Levenshtein-Parameter direkt an der SearchEngine setzen
926 m_pSearchEngine
->SetLevRelaxed(aParams
.bLevRelaxed
);
927 m_pSearchEngine
->SetLevOther(aParams
.nLevOther
);
928 m_pSearchEngine
->SetLevShorter(aParams
.nLevShorter
);
929 m_pSearchEngine
->SetLevLonger(aParams
.nLevLonger
);
931 m_pSearchEngine
->SetTransliterationFlags( aParams
.getTransliterationFlags( ) );
933 m_rbSearchForText
.Check(sal_False
);
934 m_rbSearchForNull
.Check(sal_False
);
935 m_rbSearchForNotNull
.Check(sal_False
);
936 switch (aParams
.nSearchForType
)
938 case 1: m_rbSearchForNull
.Check(sal_True
); break;
939 case 2: m_rbSearchForNotNull
.Check(sal_True
); break;
940 default: m_rbSearchForText
.Check(sal_True
); break;
942 LINK(this, FmSearchDialog
, OnClickedFieldRadios
).Call(&m_rbSearchForText
);
945 //------------------------------------------------------------------------
946 void FmSearchDialog::SaveParams() const
951 FmSearchParams aCurrentSettings
;
953 aCurrentSettings
.aHistory
.realloc( m_cmbSearchText
.GetEntryCount() );
954 ::rtl::OUString
* pHistory
= aCurrentSettings
.aHistory
.getArray();
955 for (sal_uInt16 i
=0; i
<m_cmbSearchText
.GetEntryCount(); ++i
, ++pHistory
)
956 *pHistory
= m_cmbSearchText
.GetEntry(i
);
958 aCurrentSettings
.sSingleSearchField
= m_lbField
.GetSelectEntry();
959 aCurrentSettings
.bAllFields
= m_rbAllFields
.IsChecked();
960 aCurrentSettings
.nPosition
= m_pSearchEngine
->GetPosition();
961 aCurrentSettings
.bUseFormatter
= m_pSearchEngine
->GetFormatterUsing();
962 aCurrentSettings
.setCaseSensitive ( m_pSearchEngine
->GetCaseSensitive() );
963 aCurrentSettings
.bBackwards
= !m_pSearchEngine
->GetDirection();
964 aCurrentSettings
.bWildcard
= m_pSearchEngine
->GetWildcard();
965 aCurrentSettings
.bRegular
= m_pSearchEngine
->GetRegular();
966 aCurrentSettings
.bApproxSearch
= m_pSearchEngine
->GetLevenshtein();
967 aCurrentSettings
.bLevRelaxed
= m_pSearchEngine
->GetLevRelaxed();
968 aCurrentSettings
.nLevOther
= m_pSearchEngine
->GetLevOther();
969 aCurrentSettings
.nLevShorter
= m_pSearchEngine
->GetLevShorter();
970 aCurrentSettings
.nLevLonger
= m_pSearchEngine
->GetLevLonger();
972 aCurrentSettings
.bSoundsLikeCJK
= m_pSearchEngine
->GetTransliteration();
973 aCurrentSettings
.setTransliterationFlags ( m_pSearchEngine
->GetTransliterationFlags() );
975 if (m_rbSearchForNull
.IsChecked())
976 aCurrentSettings
.nSearchForType
= 1;
977 else if (m_rbSearchForNotNull
.IsChecked())
978 aCurrentSettings
.nSearchForType
= 2;
980 aCurrentSettings
.nSearchForType
= 0;
982 m_pConfig
->setParams( aCurrentSettings
);