Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include <rtl/strbuf.hxx>
31 : : #include "svx/fmresids.hrc"
32 : : #include "svx/fmtools.hxx"
33 : : #include "svx/fmsrccfg.hxx"
34 : : #include <tools/debug.hxx>
35 : : #include <tools/diagnose_ex.h>
36 : : #include <tools/wldcrd.hxx>
37 : : #include <vcl/msgbox.hxx>
38 : : #include <tools/shl.hxx>
39 : : #include <svx/dialmgr.hxx>
40 : : #include <cppuhelper/servicefactory.hxx>
41 : : #include <vcl/svapp.hxx>
42 : : #include <unotools/textsearch.hxx>
43 : : #include <com/sun/star/util/SearchOptions.hpp>
44 : : #include <com/sun/star/util/SearchAlgorithms.hpp>
45 : : #include <com/sun/star/util/SearchResult.hpp>
46 : : #include <com/sun/star/util/SearchFlags.hpp>
47 : : #include <com/sun/star/lang/Locale.hpp>
48 : : #include <com/sun/star/i18n/TransliterationModules.hpp>
49 : : #include <com/sun/star/i18n/CollatorOptions.hpp>
50 : :
51 : : #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
52 : : #include <com/sun/star/util/XNumberFormatter.hpp>
53 : : #include <com/sun/star/util/NumberFormat.hpp>
54 : : #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
55 : : #include <com/sun/star/util/XNumberFormats.hpp>
56 : : #include <comphelper/processfactory.hxx>
57 : :
58 : : #include "fmprop.hrc"
59 : : #include "fmservs.hxx"
60 : : #include "svx/fmsrcimp.hxx"
61 : : #include <svx/fmsearch.hxx>
62 : :
63 : : #include <comphelper/numbers.hxx>
64 : : #include <unotools/syslocale.hxx>
65 : :
66 : : #define EQUAL_BOOKMARKS(a, b) a == b
67 : :
68 : : #define IFACECAST(c) ((const Reference< XInterface >&)c)
69 : :
70 : : using namespace ::com::sun::star::uno;
71 : : using namespace ::com::sun::star::util;
72 : : using namespace ::com::sun::star::lang;
73 : : using namespace ::com::sun::star::sdbc;
74 : : using namespace ::com::sun::star::i18n;
75 : : using namespace ::com::sun::star::beans;
76 : : using namespace ::svxform;
77 : :
78 : :
79 : : //========================================================================
80 : : // = FmSearchThread
81 : : //------------------------------------------------------------------------
82 : 0 : void FmSearchThread::run()
83 : : {
84 : 0 : m_pEngine->SearchNextImpl();
85 : 0 : };
86 : :
87 : : //------------------------------------------------------------------------
88 : 0 : void FmSearchThread::onTerminated()
89 : : {
90 [ # # ]: 0 : if (m_aTerminationHdl.IsSet())
91 : 0 : m_aTerminationHdl.Call(this);
92 [ # # ]: 0 : delete this;
93 : 0 : }
94 : :
95 : : //========================================================================
96 : : // = FmRecordCountListener
97 : :
98 : : // SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject);
99 : :
100 : : DBG_NAME(FmRecordCountListener);
101 : : //------------------------------------------------------------------------
102 [ # # ]: 0 : FmRecordCountListener::FmRecordCountListener(const Reference< ::com::sun::star::sdbc::XResultSet > & dbcCursor)
103 : : {
104 : : DBG_CTOR(FmRecordCountListener,NULL);
105 : :
106 [ # # ][ # # ]: 0 : m_xListening = Reference< ::com::sun::star::beans::XPropertySet > (dbcCursor, UNO_QUERY);
107 [ # # ]: 0 : if (!m_xListening.is())
108 : 0 : return;
109 : :
110 [ # # ][ # # ]: 0 : if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL)))
[ # # ][ # # ]
[ # # ]
111 : : {
112 [ # # ]: 0 : m_xListening = NULL;
113 : : // there's nothing to do as the record count is already known
114 : 0 : return;
115 : : }
116 : :
117 [ # # ][ # # ]: 0 : m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
[ # # ][ # # ]
118 : : }
119 : :
120 : : //------------------------------------------------------------------------
121 : 0 : Link FmRecordCountListener::SetPropChangeHandler(const Link& lnk)
122 : : {
123 : 0 : Link lnkReturn = m_lnkWhoWantsToKnow;
124 : 0 : m_lnkWhoWantsToKnow = lnk;
125 : :
126 [ # # ]: 0 : if (m_xListening.is())
127 : 0 : NotifyCurrentCount();
128 : :
129 : 0 : return lnkReturn;
130 : : }
131 : :
132 : : //------------------------------------------------------------------------
133 : 0 : FmRecordCountListener::~FmRecordCountListener()
134 : : {
135 : :
136 : : DBG_DTOR(FmRecordCountListener,NULL);
137 [ # # ]: 0 : }
138 : :
139 : : //------------------------------------------------------------------------
140 : 0 : void FmRecordCountListener::DisConnect()
141 : : {
142 [ # # ]: 0 : if(m_xListening.is())
143 [ # # ][ # # ]: 0 : m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
144 : 0 : m_xListening = NULL;
145 : 0 : }
146 : :
147 : : //------------------------------------------------------------------------
148 : 0 : void SAL_CALL FmRecordCountListener::disposing(const ::com::sun::star::lang::EventObject& /*Source*/) throw( RuntimeException )
149 : : {
150 : : DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !");
151 : 0 : DisConnect();
152 : 0 : }
153 : :
154 : : //------------------------------------------------------------------------
155 : 0 : void FmRecordCountListener::NotifyCurrentCount()
156 : : {
157 [ # # ]: 0 : if (m_lnkWhoWantsToKnow.IsSet())
158 : : {
159 : : DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?");
160 [ # # ][ # # ]: 0 : void* pTheCount = (void*)(sal_IntPtr)::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT));
161 : 0 : m_lnkWhoWantsToKnow.Call(pTheCount);
162 : : }
163 : 0 : }
164 : :
165 : : //------------------------------------------------------------------------
166 : 0 : void FmRecordCountListener::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& /*evt*/) throw(::com::sun::star::uno::RuntimeException)
167 : : {
168 : 0 : NotifyCurrentCount();
169 : 0 : }
170 : :
171 : : //========================================================================
172 : : // FmSearchEngine - local classes
173 : : //------------------------------------------------------------------------
174 : 0 : SimpleTextWrapper::SimpleTextWrapper(const Reference< ::com::sun::star::awt::XTextComponent > & _xText)
175 : 0 : :ControlTextWrapper(_xText.get())
176 [ # # ]: 0 : ,m_xText(_xText)
177 : : {
178 : : DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !");
179 : 0 : }
180 : :
181 : : //------------------------------------------------------------------------
182 : 0 : ::rtl::OUString SimpleTextWrapper::getCurrentText() const
183 : : {
184 : 0 : return m_xText->getText();
185 : : }
186 : :
187 : : //------------------------------------------------------------------------
188 : 0 : ListBoxWrapper::ListBoxWrapper(const Reference< ::com::sun::star::awt::XListBox > & _xBox)
189 : 0 : :ControlTextWrapper(_xBox.get())
190 [ # # ]: 0 : ,m_xBox(_xBox)
191 : : {
192 : : DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !");
193 : 0 : }
194 : :
195 : : //------------------------------------------------------------------------
196 : 0 : ::rtl::OUString ListBoxWrapper::getCurrentText() const
197 : : {
198 : 0 : return m_xBox->getSelectedItem();
199 : : }
200 : :
201 : : //------------------------------------------------------------------------
202 : 0 : CheckBoxWrapper::CheckBoxWrapper(const Reference< ::com::sun::star::awt::XCheckBox > & _xBox)
203 : 0 : :ControlTextWrapper(_xBox.get())
204 [ # # ]: 0 : ,m_xBox(_xBox)
205 : : {
206 : : DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !");
207 : 0 : }
208 : :
209 : : //------------------------------------------------------------------------
210 : 0 : ::rtl::OUString CheckBoxWrapper::getCurrentText() const
211 : : {
212 [ # # # ]: 0 : switch ((TriState)m_xBox->getState())
213 : : {
214 : 0 : case STATE_NOCHECK: return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0"));
215 : 0 : case STATE_CHECK: return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("1"));
216 : 0 : default: break;
217 : : }
218 : 0 : return rtl::OUString();
219 : : }
220 : :
221 : : //========================================================================
222 : : // = FmSearchEngine
223 : : //------------------------------------------------------------------------
224 : 0 : sal_Bool FmSearchEngine::MoveCursor()
225 : : {
226 : 0 : sal_Bool bSuccess = sal_True;
227 : : try
228 : : {
229 [ # # ]: 0 : if (m_bForward)
230 [ # # ][ # # ]: 0 : if (m_xSearchCursor.isLast())
231 [ # # ]: 0 : m_xSearchCursor.first();
232 : : else
233 [ # # ]: 0 : m_xSearchCursor.next();
234 : : else
235 [ # # ][ # # ]: 0 : if (m_xSearchCursor.isFirst())
236 : : {
237 [ # # ]: 0 : FmRecordCountListener* prclListener = new FmRecordCountListener(m_xSearchCursor);
238 : 0 : prclListener->acquire();
239 [ # # # # : 0 : prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount));
# ][ # # ]
240 : :
241 [ # # ]: 0 : m_xSearchCursor.last();
242 : :
243 [ # # ]: 0 : prclListener->DisConnect();
244 : 0 : prclListener->release();
245 : : }
246 : : else
247 [ # # ]: 0 : m_xSearchCursor.previous();
248 : : }
249 : 0 : catch(::com::sun::star::sdbc::SQLException const& e)
250 : : {
251 : : #if OSL_DEBUG_LEVEL > 0
252 : : rtl::OStringBuffer sDebugMessage(RTL_CONSTASCII_STRINGPARAM(
253 : : "FmSearchEngine::MoveCursor : catched a DatabaseException ("));
254 : : sDebugMessage.append(rtl::OUStringToOString(e.SQLState, RTL_TEXTENCODING_ASCII_US));
255 : : sDebugMessage.append(RTL_CONSTASCII_STRINGPARAM(") !"));
256 : : OSL_FAIL(sDebugMessage.getStr());
257 : : #else
258 : : (void)e;
259 : : #endif
260 : 0 : bSuccess = sal_False;
261 : : }
262 : 0 : catch(Exception const& e)
263 : : {
264 : : #if OSL_DEBUG_LEVEL > 0
265 : : rtl::OStringBuffer sDebugMessage(RTL_CONSTASCII_STRINGPARAM(
266 : : "FmSearchEngine::MoveCursor : catched an Exception ("));
267 : : sDebugMessage.append(rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US));
268 : : sDebugMessage.append(RTL_CONSTASCII_STRINGPARAM(") !"));
269 : : OSL_FAIL(sDebugMessage.getStr());
270 : : #else
271 : : (void)e;
272 : : #endif
273 : 0 : bSuccess = sal_False;
274 : : }
275 : 0 : catch(...)
276 : : {
277 : : OSL_FAIL("FmSearchEngine::MoveCursor : catched an unknown Exception !");
278 : 0 : bSuccess = sal_False;
279 : : }
280 : :
281 : 0 : return bSuccess;
282 : : }
283 : :
284 : : //------------------------------------------------------------------------
285 : 0 : sal_Bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollectionIterator& iter, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
286 : : {
287 : 0 : sal_Bool bSuccess(sal_True);
288 [ # # ]: 0 : if (m_bForward)
289 : : {
290 : 0 : ++iter;
291 : 0 : ++nPos;
292 [ # # ]: 0 : if (iter == iterEnd)
293 : : {
294 : 0 : bSuccess = MoveCursor();
295 : 0 : iter = iterBegin;
296 : 0 : nPos = 0;
297 : : }
298 : : } else
299 : : {
300 [ # # ]: 0 : if (iter == iterBegin)
301 : : {
302 : 0 : bSuccess = MoveCursor();
303 : 0 : iter = iterEnd;
304 : 0 : nPos = iter-iterBegin;
305 : : }
306 : 0 : --iter;
307 : 0 : --nPos;
308 : : }
309 : 0 : return bSuccess;
310 : : }
311 : :
312 : : //------------------------------------------------------------------------
313 : 0 : void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< ::com::sun::star::container::XIndexAccess > & xAllFields, sal_Int32 nField)
314 : : {
315 : : DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ),
316 : : "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" );
317 : :
318 : : // das Feld selber
319 : 0 : Reference< XInterface > xCurrentField;
320 [ # # ][ # # ]: 0 : xAllFields->getByIndex(nField) >>= xCurrentField;
[ # # ]
321 : :
322 : : // von dem weiss ich jetzt, dass es den DatabaseRecord-Service unterstuetzt (hoffe ich)
323 : : // fuer den FormatKey und den Typ brauche ich das PropertySet
324 [ # # ]: 0 : Reference< ::com::sun::star::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY);
325 : :
326 : : // die FieldInfo dazu aufbauen
327 [ # # ]: 0 : FieldInfo fiCurrent;
328 [ # # ][ # # ]: 0 : fiCurrent.xContents = Reference< ::com::sun::star::sdb::XColumn > (xCurrentField, UNO_QUERY);
329 [ # # ][ # # ]: 0 : fiCurrent.nFormatKey = ::comphelper::getINT32(xProperties->getPropertyValue(FM_PROP_FORMATKEY));
[ # # ][ # # ]
330 : 0 : fiCurrent.bDoubleHandling = sal_False;
331 [ # # ]: 0 : if (m_xFormatSupplier.is())
332 : : {
333 [ # # ][ # # ]: 0 : Reference< ::com::sun::star::util::XNumberFormats > xNumberFormats(m_xFormatSupplier->getNumberFormats());
334 : :
335 [ # # ]: 0 : sal_Int16 nFormatType = ::comphelper::getNumberFormatType(xNumberFormats, fiCurrent.nFormatKey) & ~((sal_Int16)::com::sun::star::util::NumberFormat::DEFINED);
336 : 0 : fiCurrent.bDoubleHandling = (nFormatType != ::com::sun::star::util::NumberFormat::TEXT);
337 : : }
338 : :
339 : : // und merken
340 [ # # ][ # # ]: 0 : m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent);
341 : :
342 : 0 : }
343 : : //------------------------------------------------------------------------
344 : 0 : ::rtl::OUString FmSearchEngine::FormatField(const FieldInfo& rField)
345 : : {
346 : : DBG_ASSERT(!m_bUsingTextComponents, "FmSearchEngine::FormatField : im UsingTextComponents-Mode bitte FormatField(sal_Int32) benutzen !");
347 : :
348 [ # # ]: 0 : if (!m_xFormatter.is())
349 : 0 : return ::rtl::OUString();
350 : : // sonst werden Datumsflder zum Beispiel zu irgendeinem Default-Wert formatiert
351 : :
352 : 0 : ::rtl::OUString sReturn;
353 : : try
354 : : {
355 [ # # ]: 0 : if (rField.bDoubleHandling)
356 : : {
357 [ # # ][ # # ]: 0 : double fValue = rField.xContents->getDouble();
358 [ # # ][ # # ]: 0 : if (!rField.xContents->wasNull())
[ # # ]
359 [ # # ][ # # ]: 0 : sReturn = m_xFormatter->convertNumberToString(rField.nFormatKey, fValue);
360 : : }
361 : : else
362 : : {
363 [ # # ][ # # ]: 0 : ::rtl::OUString sValue = rField.xContents->getString();
364 [ # # ][ # # ]: 0 : if (!rField.xContents->wasNull())
[ # # ]
365 [ # # ][ # # ]: 0 : sReturn = m_xFormatter->formatString(rField.nFormatKey, sValue);
366 : : }
367 : : }
368 [ # # ]: 0 : catch(...)
369 : : {
370 : : }
371 : :
372 : :
373 : 0 : return sReturn;
374 : : }
375 : :
376 : : //------------------------------------------------------------------------
377 : 0 : ::rtl::OUString FmSearchEngine::FormatField(sal_Int32 nWhich)
378 : : {
379 [ # # ]: 0 : if (m_bUsingTextComponents)
380 : : {
381 : : DBG_ASSERT((sal_uInt32)nWhich < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !");
382 : : DBG_ASSERT(m_aControlTexts[nWhich] != NULL, "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !");
383 : : DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !");
384 : :
385 [ # # ]: 0 : if (m_nCurrentFieldIndex != -1)
386 : : {
387 : : DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
388 : : // analoge Situation wie unten
389 : 0 : nWhich = m_nCurrentFieldIndex;
390 : : }
391 : :
392 : : DBG_ASSERT((nWhich >= 0) && ((sal_uInt32)nWhich < m_aControlTexts.size()),
393 : : "FmSearchEngine::FormatField : invalid argument nWhich !");
394 [ # # ]: 0 : return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText();
395 : : }
396 : : else
397 : : {
398 [ # # ]: 0 : if (m_nCurrentFieldIndex != -1)
399 : : {
400 : : DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
401 : : // ich bin im single-field-modus, da ist auch die richtige Feld-Nummer erlaubt, obwohl dann der richtige ::com::sun::star::sdbcx::Index
402 : : // fuer meinen Array-Zugriff natuerlich 0 ist
403 : 0 : nWhich = 0;
404 : : }
405 : :
406 : : DBG_ASSERT((nWhich>=0) && (nWhich < (m_arrUsedFields.end() - m_arrUsedFields.begin())),
407 : : "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
408 : 0 : return FormatField(m_arrUsedFields[nWhich]);
409 : : }
410 : : }
411 : :
412 : : //------------------------------------------------------------------------
413 : 0 : FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchSpecial(sal_Bool _bSearchForNull, sal_Int32& nFieldPos,
414 : : FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
415 : : {
416 : : // die Startposition merken
417 : 0 : Any aStartMark;
418 [ # # ]: 0 : try { aStartMark = m_xSearchCursor.getBookmark(); }
419 [ # # # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
420 : 0 : FieldCollectionIterator iterInitialField = iterFieldLoop;
421 : :
422 : : // --------------------------------------------------------------
423 : 0 : sal_Bool bFound(sal_False);
424 : 0 : sal_Bool bMovedAround(sal_False);
425 [ # # ]: 0 : do
426 : : {
427 [ # # ]: 0 : if (m_eMode == SM_ALLOWSCHEDULE)
428 : : {
429 [ # # ]: 0 : Application::Reschedule();
430 [ # # ]: 0 : Application::Reschedule();
431 : : // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
432 : : // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
433 : : // or anything like that. So within each loop we create one user event and handle one user event (and no
434 : : // paintings and these), so the office seems to be frozen while searching.
435 : : // FS - 70226 - 02.12.99
436 : : }
437 : :
438 : : // der aktuell zu vergleichende Inhalt
439 [ # # ][ # # ]: 0 : iterFieldLoop->xContents->getString(); // needed for wasNull
[ # # ]
440 [ # # ][ # # ]: 0 : bFound = _bSearchForNull == iterFieldLoop->xContents->wasNull();
[ # # ]
441 [ # # ]: 0 : if (bFound)
442 : : break;
443 : :
444 : : // naechstes Feld (implizit naechster Datensatz, wenn noetig)
445 [ # # ][ # # ]: 0 : if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
446 : : { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
447 : : // das selbe bestimmt wieder schief geht, also Abbruch
448 : : // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
449 [ # # ]: 0 : try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
450 [ # # # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
451 : 0 : m_iterPreviousLocField = iterFieldLoop;
452 : : // und wech
453 : 0 : return SR_ERROR;
454 : : }
455 : :
456 : 0 : Any aCurrentBookmark;
457 [ # # ]: 0 : try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
458 [ # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
459 : :
460 [ # # ][ # # ]: 0 : bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
[ # # ]
461 : :
462 [ # # ]: 0 : if (nFieldPos == 0)
463 : : // das heisst, ich habe mich auf einen neuen Datensatz bewegt
464 [ # # ]: 0 : PropagateProgress(bMovedAround);
465 : : // if we moved to the starting position we don't have to propagate an 'overflow' message
466 : : // FS - 07.12.99 - 68530
467 : :
468 : : // abbrechen gefordert ?
469 [ # # ][ # # ]: 0 : if (CancelRequested())
470 [ # # ]: 0 : return SR_CANCELED;
471 : :
472 : 0 : } while (!bMovedAround);
473 : :
474 [ # # ]: 0 : return bFound ? SR_FOUND : SR_NOTFOUND;
475 : : }
476 : :
477 : : //------------------------------------------------------------------------
478 : 0 : FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchWildcard(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos,
479 : : FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
480 : : {
481 : : // die Startposition merken
482 : 0 : Any aStartMark;
483 [ # # ]: 0 : try { aStartMark = m_xSearchCursor.getBookmark(); }
484 [ # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
485 : 0 : FieldCollectionIterator iterInitialField = iterFieldLoop;
486 : :
487 [ # # ]: 0 : WildCard aSearchExpression(strExpression);
488 : :
489 : : // --------------------------------------------------------------
490 : 0 : sal_Bool bFound(sal_False);
491 : 0 : sal_Bool bMovedAround(sal_False);
492 [ # # ]: 0 : do
493 : : {
494 [ # # ]: 0 : if (m_eMode == SM_ALLOWSCHEDULE)
495 : : {
496 [ # # ]: 0 : Application::Reschedule();
497 [ # # ]: 0 : Application::Reschedule();
498 : : // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
499 : : // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
500 : : // or anything like that. So within each loop we create one user event and hanel one user event (and no
501 : : // paintings and these), so the office seems to be frozen while searching.
502 : : // FS - 70226 - 02.12.99
503 : : }
504 : :
505 : : // der aktuell zu vergleichende Inhalt
506 : 0 : ::rtl::OUString sCurrentCheck;
507 [ # # ]: 0 : if (m_bFormatter)
508 [ # # ]: 0 : sCurrentCheck = FormatField(nFieldPos);
509 : : else
510 [ # # ][ # # ]: 0 : sCurrentCheck = iterFieldLoop->xContents->getString();
[ # # ]
511 : :
512 [ # # ][ # # ]: 0 : if (!GetCaseSensitive())
513 : : // norm the string
514 [ # # ]: 0 : sCurrentCheck = m_aCharacterClassficator.lowercase(sCurrentCheck);
515 : :
516 : : // jetzt ist der Test einfach ...
517 [ # # ][ # # ]: 0 : bFound = aSearchExpression.Matches(sCurrentCheck);
[ # # # # ]
518 : :
519 [ # # ]: 0 : if (bFound)
520 : : break;
521 : :
522 : : // naechstes Feld (implizit naechster Datensatz, wenn noetig)
523 [ # # ][ # # ]: 0 : if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
524 : : { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
525 : : // das selbe bestimmt wieder schief geht, also Abbruch
526 : : // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
527 [ # # ]: 0 : try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
528 [ # # # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
529 : 0 : m_iterPreviousLocField = iterFieldLoop;
530 : : // und wech
531 : 0 : return SR_ERROR;
532 : : }
533 : :
534 : 0 : Any aCurrentBookmark;
535 [ # # ]: 0 : try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
536 [ # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
537 : :
538 [ # # ][ # # ]: 0 : bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
[ # # ]
539 : :
540 [ # # ]: 0 : if (nFieldPos == 0)
541 : : // das heisst, ich habe mich auf einen neuen Datensatz bewegt
542 [ # # ]: 0 : PropagateProgress(bMovedAround);
543 : : // if we moved to the starting position we don't have to propagate an 'overflow' message
544 : : // FS - 07.12.99 - 68530
545 : :
546 : : // abbrechen gefordert ?
547 [ # # ][ # # ]: 0 : if (CancelRequested())
548 [ # # ]: 0 : return SR_CANCELED;
[ # # # ]
549 : :
550 : 0 : } while (!bMovedAround);
551 : :
552 [ # # ][ # # ]: 0 : return bFound ? SR_FOUND : SR_NOTFOUND;
553 : : }
554 : :
555 : : //------------------------------------------------------------------------
556 : 0 : FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchRegularApprox(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos,
557 : : FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
558 : : {
559 : : DBG_ASSERT(m_bLevenshtein || m_bRegular,
560 : : "FmSearchEngine::SearchRegularApprox : ungueltiger Suchmodus !");
561 : : DBG_ASSERT(!m_bLevenshtein || !m_bRegular,
562 : : "FmSearchEngine::SearchRegularApprox : kann nicht nach regulaeren Ausdruecken und nach Aehnlichkeiten gleichzeitig suchen !");
563 : :
564 : : // Startposition merken
565 : 0 : Any aStartMark;
566 [ # # ]: 0 : try { aStartMark = m_xSearchCursor.getBookmark(); }
567 [ # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
568 : 0 : FieldCollectionIterator iterInitialField = iterFieldLoop;
569 : :
570 : : // Parameter sammeln
571 : 0 : SearchOptions aParam;
572 [ # # ]: 0 : aParam.algorithmType = m_bRegular ? SearchAlgorithms_REGEXP : SearchAlgorithms_APPROXIMATE;
573 : 0 : aParam.searchFlag = 0;
574 : 0 : aParam.transliterateFlags = GetTransliterationFlags();
575 [ # # ]: 0 : if ( !GetTransliteration() )
576 : : { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH
577 : 0 : aParam.transliterateFlags &= TransliterationModules_IGNORE_CASE | TransliterationModules_IGNORE_WIDTH;
578 : : }
579 [ # # ]: 0 : if (m_bLevenshtein)
580 : : {
581 [ # # ]: 0 : if (m_bLevRelaxed)
582 : 0 : aParam.searchFlag |= SearchFlags::LEV_RELAXED;
583 : 0 : aParam.changedChars = m_nLevOther;
584 : 0 : aParam.deletedChars = m_nLevShorter;
585 : 0 : aParam.insertedChars = m_nLevLonger;
586 : : }
587 : 0 : aParam.searchString = strExpression;
588 [ # # ][ # # ]: 0 : aParam.Locale = SvtSysLocale().GetLocaleData().getLocale();
[ # # ][ # # ]
589 [ # # ]: 0 : ::utl::TextSearch aLocalEngine(aParam);
590 : :
591 : : // --------------------------------------------------------------
592 : 0 : bool bFound = false;
593 : 0 : sal_Bool bMovedAround(sal_False);
594 [ # # ]: 0 : do
595 : : {
596 [ # # ]: 0 : if (m_eMode == SM_ALLOWSCHEDULE)
597 : : {
598 [ # # ]: 0 : Application::Reschedule();
599 [ # # ]: 0 : Application::Reschedule();
600 : : // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
601 : : // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
602 : : // or anything like that. So within each loop we create one user event and handle one user event (and no
603 : : // paintings and these), so the office seems to be frozen while searching.
604 : : // FS - 70226 - 02.12.99
605 : : }
606 : :
607 : : // der aktuell zu vergleichende Inhalt
608 : 0 : ::rtl::OUString sCurrentCheck;
609 [ # # ]: 0 : if (m_bFormatter)
610 [ # # ]: 0 : sCurrentCheck = FormatField(nFieldPos);
611 : : else
612 [ # # ][ # # ]: 0 : sCurrentCheck = iterFieldLoop->xContents->getString();
[ # # ]
613 : :
614 : : // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it)
615 : :
616 : 0 : xub_StrLen nStart = 0, nEnd = (xub_StrLen)sCurrentCheck.getLength();
617 [ # # ]: 0 : bFound = aLocalEngine.SearchFrwrd(sCurrentCheck, &nStart, &nEnd);
[ # # # # ]
[ # # ]
618 : : // das heisst hier 'forward' aber das bezieht sich nur auf die Suche innerhalb von sCurrentCheck, hat also mit
619 : : // der Richtung meines Datensatz-Durchwanderns nix zu tun (darum kuemmert sich MoveField)
620 : :
621 : : // checken, ob die Position stimmt
622 [ # # ]: 0 : if (bFound)
623 : : {
624 [ # # # # ]: 0 : switch (m_nPosition)
625 : : {
626 : : case MATCHING_WHOLETEXT :
627 [ # # ]: 0 : if (nEnd != sCurrentCheck.getLength())
628 : : {
629 : 0 : bFound = false;
630 : 0 : break;
631 : : }
632 : : // laeuft in den naechsten Case rein !
633 : : case MATCHING_BEGINNING :
634 [ # # ]: 0 : if (nStart != 0)
635 : 0 : bFound = false;
636 : 0 : break;
637 : : case MATCHING_END :
638 [ # # ]: 0 : if (nEnd != sCurrentCheck.getLength())
639 : 0 : bFound = false;
640 : 0 : break;
641 : : }
642 : : }
643 : :
644 [ # # ]: 0 : if (bFound) // immer noch ?
645 : : break;
646 : :
647 : : // naechstes Feld (implizit naechster Datensatz, wenn noetig)
648 [ # # ][ # # ]: 0 : if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
649 : : { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
650 : : // das selbe bestimmt wieder schief geht, also Abbruch (ohne Fehlermeldung, von der erwarte ich, dass sie im Move
651 : : // angezeigt wurde)
652 : : // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
653 [ # # ]: 0 : try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
654 [ # # # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
655 : 0 : m_iterPreviousLocField = iterFieldLoop;
656 : : // und wech
657 : 0 : return SR_ERROR;
658 : : }
659 : :
660 : 0 : Any aCurrentBookmark;
661 [ # # ]: 0 : try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
662 [ # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
663 [ # # ][ # # ]: 0 : bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
[ # # ]
664 : :
665 [ # # ]: 0 : if (nFieldPos == 0)
666 : : // das heisst, ich habe mich auf einen neuen Datensatz bewegt
667 [ # # ]: 0 : PropagateProgress(bMovedAround);
668 : : // if we moved to the starting position we don't have to propagate an 'overflow' message
669 : : // FS - 07.12.99 - 68530
670 : :
671 : : // abbrechen gefordert ?
672 [ # # ][ # # ]: 0 : if (CancelRequested())
673 [ # # ]: 0 : return SR_CANCELED;
[ # # # ]
674 : :
675 : 0 : } while (!bMovedAround);
676 : :
677 [ # # ][ # # ]: 0 : return bFound ? SR_FOUND : SR_NOTFOUND;
[ # # ]
678 : : }
679 : :
680 : :
681 : : DBG_NAME(FmSearchEngine);
682 : : //------------------------------------------------------------------------
683 : 0 : FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB,
684 : : const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields,
685 : : const Reference< XNumberFormatsSupplier > & xFormatSupplier, FMSEARCH_MODE eMode)
686 : :
687 : : :m_xSearchCursor(xCursor)
688 : : ,m_xFormatSupplier(xFormatSupplier)
689 [ # # ][ # # ]: 0 : ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() )
[ # # ][ # # ]
690 : : ,m_aStringCompare( _rxORB )
691 : : ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
692 : : ,m_bUsingTextComponents(sal_False)
693 : : ,m_eSearchForType(SEARCHFOR_STRING)
694 : : ,m_srResult(SR_FOUND)
695 : : ,m_bSearchingCurrently(sal_False)
696 : : ,m_bCancelAsynchRequest(sal_False)
697 : : ,m_eMode(eMode)
698 : : ,m_bFormatter(sal_False)
699 : : ,m_bForward(sal_False)
700 : : ,m_bWildcard(sal_False)
701 : : ,m_bRegular(sal_False)
702 : : ,m_bLevenshtein(sal_False)
703 : : ,m_bTransliteration(sal_False)
704 : : ,m_bLevRelaxed(sal_False)
705 : : ,m_nLevOther(0)
706 : : ,m_nLevShorter(0)
707 : : ,m_nLevLonger(0)
708 : : ,m_nPosition(MATCHING_ANYWHERE)
709 [ # # ][ # # ]: 0 : ,m_nTransliterationFlags(0)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
710 : : {
711 : : DBG_CTOR(FmSearchEngine,NULL);
712 : :
713 : : m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter > (::comphelper::getProcessServiceFactory()
714 [ # # ][ # # ]: 0 : ->createInstance(FM_NUMBER_FORMATTER), UNO_QUERY);
[ # # ][ # # ]
[ # # ][ # # ]
715 [ # # ]: 0 : if (m_xFormatter.is())
716 [ # # ][ # # ]: 0 : m_xFormatter->attachNumberFormatsSupplier(m_xFormatSupplier);
717 : :
718 [ # # ]: 0 : Init(sVisibleFields);
719 : 0 : }
720 : :
721 : : //------------------------------------------------------------------------
722 : 0 : FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB,
723 : : const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields,
724 : : const InterfaceArray& arrFields, FMSEARCH_MODE eMode)
725 : : :m_xSearchCursor(xCursor)
726 [ # # ][ # # ]: 0 : ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() )
[ # # ][ # # ]
727 : : ,m_aStringCompare( _rxORB )
728 : : ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
729 : : ,m_bUsingTextComponents(sal_True)
730 : : ,m_xOriginalIterator(xCursor)
731 : : ,m_xClonedIterator(m_xOriginalIterator, sal_True)
732 : : ,m_eSearchForType(SEARCHFOR_STRING)
733 : : ,m_srResult(SR_FOUND)
734 : : ,m_bSearchingCurrently(sal_False)
735 : : ,m_bCancelAsynchRequest(sal_False)
736 : : ,m_eMode(eMode)
737 : : ,m_bFormatter(sal_True) // das muss konsistent sein mit m_xSearchCursor, der i.A. == m_xOriginalIterator ist
738 : : ,m_bForward(sal_False)
739 : : ,m_bWildcard(sal_False)
740 : : ,m_bRegular(sal_False)
741 : : ,m_bLevenshtein(sal_False)
742 : : ,m_bTransliteration(sal_False)
743 : : ,m_bLevRelaxed(sal_False)
744 : : ,m_nLevOther(0)
745 : : ,m_nLevShorter(0)
746 : : ,m_nLevLonger(0)
747 : : ,m_nPosition(MATCHING_ANYWHERE)
748 [ # # ][ # # ]: 0 : ,m_nTransliterationFlags(0)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
749 : : {
750 : : DBG_CTOR(FmSearchEngine,NULL);
751 : :
752 [ # # ]: 0 : fillControlTexts(arrFields);
753 [ # # ]: 0 : Init(sVisibleFields);
754 : 0 : }
755 : :
756 : : //------------------------------------------------------------------------
757 [ # # ][ # # ]: 0 : FmSearchEngine::~FmSearchEngine()
[ # # ][ # # ]
[ # # ]
758 : : {
759 [ # # ]: 0 : clearControlTexts();
760 : :
761 : : DBG_DTOR(FmSearchEngine,NULL);
762 [ # # ]: 0 : }
763 : :
764 : : //------------------------------------------------------------------------
765 : 0 : void FmSearchEngine::SetIgnoreWidthCJK(sal_Bool bSet)
766 : : {
767 [ # # ]: 0 : if (bSet)
768 : 0 : m_nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH;
769 : : else
770 : 0 : m_nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH;
771 : 0 : }
772 : :
773 : : //------------------------------------------------------------------------
774 : 0 : sal_Bool FmSearchEngine::GetIgnoreWidthCJK() const
775 : : {
776 : 0 : return 0 != (m_nTransliterationFlags & TransliterationModules_IGNORE_WIDTH);
777 : : }
778 : :
779 : : //------------------------------------------------------------------------
780 : 0 : void FmSearchEngine::SetCaseSensitive(sal_Bool bSet)
781 : : {
782 [ # # ]: 0 : if (bSet)
783 : 0 : m_nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE;
784 : : else
785 : 0 : m_nTransliterationFlags |= TransliterationModules_IGNORE_CASE;
786 : 0 : }
787 : :
788 : : //------------------------------------------------------------------------
789 : 0 : sal_Bool FmSearchEngine::GetCaseSensitive() const
790 : : {
791 : 0 : return 0 == (m_nTransliterationFlags & TransliterationModules_IGNORE_CASE);
792 : : }
793 : :
794 : : //------------------------------------------------------------------------
795 : 0 : void FmSearchEngine::clearControlTexts()
796 : : {
797 [ # # ][ # # ]: 0 : for ( ControlTextSuppliersIterator aIter = m_aControlTexts.begin();
798 : 0 : aIter < m_aControlTexts.end();
799 : : ++aIter
800 : : )
801 : : {
802 [ # # ][ # # ]: 0 : delete *aIter;
803 : : }
804 : 0 : m_aControlTexts.clear();
805 : 0 : }
806 : :
807 : : //------------------------------------------------------------------------
808 : 0 : void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields)
809 : : {
810 [ # # ]: 0 : clearControlTexts();
811 : 0 : Reference< XInterface > xCurrent;
812 [ # # ]: 0 : for (sal_uInt32 i=0; i<arrFields.size(); ++i)
813 : : {
814 [ # # ][ # # ]: 0 : xCurrent = arrFields.at(i);
815 : : DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !");
816 : : // check which type of control this is
817 [ # # ]: 0 : Reference< ::com::sun::star::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY);
818 [ # # ]: 0 : if (xAsText.is())
819 : : {
820 [ # # ][ # # ]: 0 : m_aControlTexts.insert(m_aControlTexts.end(), new SimpleTextWrapper(xAsText));
[ # # ]
821 : 0 : continue;
822 : : }
823 : :
824 [ # # ]: 0 : Reference< ::com::sun::star::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY);
825 [ # # ]: 0 : if (xAsListBox.is())
826 : : {
827 [ # # ][ # # ]: 0 : m_aControlTexts.insert(m_aControlTexts.end(), new ListBoxWrapper(xAsListBox));
[ # # ]
828 : 0 : continue;
829 : : }
830 : :
831 [ # # ]: 0 : Reference< ::com::sun::star::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY);
832 : : DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !");
833 : : // we don't have any more options ...
834 [ # # ][ # # ]: 0 : m_aControlTexts.insert(m_aControlTexts.end(), new CheckBoxWrapper(xAsCheckBox));
[ # # ]
835 [ # # ][ # # ]: 0 : }
836 : 0 : }
837 : :
838 : : //------------------------------------------------------------------------
839 : 0 : void FmSearchEngine::Init(const ::rtl::OUString& sVisibleFields)
840 : : {
841 : : // analyze the fields
842 : : // additionally, create the mapping: because the list of used columns can be shorter than the list
843 : : // of columns of the cursor, we need a mapping: "used column numer n" -> "cursor column m"
844 : 0 : m_arrFieldMapping.clear();
845 : :
846 : : // important: The case of the columns does not need to be exact - for instance:
847 : : // - a user created a form which works on a table, for which the driver returns a column name "COLUMN"
848 : : // - the driver itself works case-insensitve with column names
849 : : // - a control in the form is bound to "column" - not the different case
850 : : // In such a scenario, the form and the field would work okay, but we here need to case for the different case
851 : : // explicitly
852 : : // #i8755#
853 : :
854 : : // so first of all, check if the database handles identifiers case sensitive
855 : 0 : Reference< XConnection > xConn;
856 : 0 : Reference< XDatabaseMetaData > xMeta;
857 [ # # ]: 0 : Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY );
858 [ # # ]: 0 : if ( xCursorProps.is() )
859 : : {
860 : : try
861 : : {
862 [ # # ][ # # ]: 0 : xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn;
[ # # ][ # # ]
[ # # ]
863 : : }
864 [ # # ]: 0 : catch( const Exception& ) { /* silent this - will be asserted below */ }
865 : : }
866 [ # # ]: 0 : if ( xConn.is() )
867 [ # # ][ # # ]: 0 : xMeta = xConn->getMetaData();
[ # # ]
868 : : OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" );
869 : :
870 : 0 : sal_Bool bCaseSensitiveIdentifiers = sal_True; // assume case sensivity
871 [ # # ]: 0 : if ( xMeta.is() )
872 [ # # ][ # # ]: 0 : bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers();
873 : :
874 : : // now that we have this information, we need a collator which is able to case (in)sentively compare strings
875 [ # # ][ # # ]: 0 : m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLocaleData().getLocale(),
[ # # ][ # # ]
876 [ # # ]: 0 : bCaseSensitiveIdentifiers ? 0 : ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
877 : :
878 : : try
879 : : {
880 : : // der Cursor kann mir einen Record (als PropertySet) liefern, dieser unterstuetzt den DatabaseRecord-Service
881 [ # # ]: 0 : Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
882 : : DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !");
883 [ # # ][ # # ]: 0 : Reference< ::com::sun::star::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns();
884 [ # # ][ # # ]: 0 : Sequence< ::rtl::OUString > seqFieldNames = xAllFieldNames->getElementNames();
885 [ # # ]: 0 : ::rtl::OUString* pFieldNames = seqFieldNames.getArray();
886 : :
887 : :
888 : 0 : ::rtl::OUString sCurrentField;
889 : 0 : ::rtl::OUString sVis(sVisibleFields.getStr());
890 : 0 : sal_Int32 nIndex = 0;
891 [ # # ]: 0 : do
892 : : {
893 : 0 : sCurrentField = sVis.getToken(0, ';' , nIndex);
894 : :
895 : : // in der Feld-Sammlung suchen
896 : 0 : sal_Int32 nFoundIndex = -1;
897 [ # # ]: 0 : for (sal_Int32 j=0; j<seqFieldNames.getLength(); ++j, ++pFieldNames)
898 : : {
899 [ # # ][ # # ]: 0 : if ( 0 == m_aStringCompare.compareString( *pFieldNames, sCurrentField ) )
900 : : {
901 : 0 : nFoundIndex = j;
902 : 0 : break;
903 : : }
904 : : }
905 : : // set the field selection back to the first
906 [ # # ]: 0 : pFieldNames = seqFieldNames.getArray();
907 : : DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Invalid field name were given !");
908 [ # # ]: 0 : m_arrFieldMapping.push_back(nFoundIndex);
909 : : }
910 [ # # ][ # # ]: 0 : while ( nIndex >= 0 );
911 : : }
912 [ # # ]: 0 : catch (const Exception&)
913 : : {
914 : : OSL_FAIL("Exception occurred!");
915 : 0 : }
916 : :
917 : 0 : }
918 : :
919 : : //------------------------------------------------------------------------
920 : 0 : void FmSearchEngine::SetFormatterUsing(sal_Bool bSet)
921 : : {
922 [ # # ]: 0 : if (m_bFormatter == bSet)
923 : 0 : return;
924 : 0 : m_bFormatter = bSet;
925 : :
926 [ # # ]: 0 : if (m_bUsingTextComponents)
927 : : {
928 : : // ich benutzte keinen Formatter, sondern TextComponents -> der SearchIterator muss angepasst werden
929 : : try
930 : : {
931 [ # # ]: 0 : if (m_bFormatter)
932 : : {
933 : : DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
934 [ # # ]: 0 : m_xSearchCursor = m_xOriginalIterator;
935 [ # # ][ # # ]: 0 : m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark());
936 : : // damit ich mit dem neuen Iterator wirklich dort weitermache, wo ich vorher aufgehoert habe
937 : : }
938 : : else
939 : : {
940 : : DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
941 [ # # ]: 0 : m_xSearchCursor = m_xClonedIterator;
942 [ # # ][ # # ]: 0 : m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark());
[ # # ]
943 : : }
944 : : }
945 : 0 : catch( const Exception& )
946 : : {
947 : : DBG_UNHANDLED_EXCEPTION();
948 : : }
949 : :
950 : : // ich muss die Fields neu binden, da der Textaustausch eventuell ueber diese Fields erfolgt und sich der unterliegende Cursor
951 : : // geaendert hat
952 : 0 : RebuildUsedFields(m_nCurrentFieldIndex, sal_True);
953 : : }
954 : : else
955 : 0 : InvalidatePreviousLoc();
956 : : }
957 : :
958 : : //------------------------------------------------------------------------
959 : 0 : void FmSearchEngine::PropagateProgress(sal_Bool _bDontPropagateOverflow)
960 : : {
961 [ # # ]: 0 : if (m_aProgressHandler.IsSet())
962 : : {
963 : 0 : FmSearchProgress aProgress;
964 : : try
965 : : {
966 : 0 : aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS;
967 [ # # ]: 0 : aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
968 [ # # ]: 0 : if (m_bForward)
969 [ # # ][ # # ]: 0 : aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst();
[ # # ]
970 : : else
971 [ # # ][ # # ]: 0 : aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast();
[ # # ]
972 : : }
973 [ # # ]: 0 : catch( const Exception& )
974 : : {
975 : : DBG_UNHANDLED_EXCEPTION();
976 : : }
977 : :
978 [ # # ]: 0 : m_aProgressHandler.Call(&aProgress);
979 : : }
980 [ # # ]: 0 : }
981 : :
982 : : //------------------------------------------------------------------------
983 : 0 : void FmSearchEngine::SearchNextImpl()
984 : : {
985 : : DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard),
986 : : "FmSearchEngine::SearchNextImpl : Suchparameter schliessen sich gegenseitig aus !");
987 : :
988 : : DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : habe ungueltigen Iterator !");
989 : :
990 : : // die Parameter der Suche
991 : 0 : ::rtl::OUString strSearchExpression(m_strSearchExpression); // brauche ich non-const
992 [ # # ][ # # ]: 0 : if (!GetCaseSensitive())
993 : : // norm the string
994 [ # # ]: 0 : strSearchExpression = m_aCharacterClassficator.lowercase(strSearchExpression);
995 : :
996 [ # # ][ # # ]: 0 : if (!m_bRegular && !m_bLevenshtein)
997 : : { // 'normale' Suche fuehre ich auf jeden Fall ueber WildCards durch, muss aber vorher je nach Modus den ::rtl::OUString anpassen
998 : :
999 [ # # ]: 0 : if (!m_bWildcard)
1000 : : { // da natuerlich in allen anderen Faellen auch * und ? im Suchstring erlaubt sind, aber nicht als WildCards zaehlen
1001 : : // sollen, muss ich normieren
1002 [ # # ]: 0 : UniString aTmp(strSearchExpression);
1003 : 0 : const rtl::OUString s_sStar("\\*");
1004 : 0 : const rtl::OUString s_sQuotation("\\?");
1005 [ # # ][ # # ]: 0 : aTmp.SearchAndReplaceAll(rtl::OUString('*'), s_sStar);
[ # # ][ # # ]
[ # # ]
1006 [ # # ][ # # ]: 0 : aTmp.SearchAndReplaceAll(rtl::OUString('?'), s_sQuotation);
[ # # ][ # # ]
[ # # ]
1007 [ # # ]: 0 : strSearchExpression = aTmp;
1008 : :
1009 [ # # # # : 0 : switch (m_nPosition)
# ]
1010 : : {
1011 : : case MATCHING_ANYWHERE :
1012 : : strSearchExpression = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")) + strSearchExpression
1013 [ # # ][ # # ]: 0 : + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*"));
1014 : 0 : break;
1015 : : case MATCHING_BEGINNING :
1016 [ # # ]: 0 : strSearchExpression = strSearchExpression + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*"));
1017 : 0 : break;
1018 : : case MATCHING_END :
1019 [ # # ]: 0 : strSearchExpression = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")) + strSearchExpression;
1020 : 0 : break;
1021 : : case MATCHING_WHOLETEXT :
1022 : 0 : break;
1023 : : default :
1024 : : OSL_FAIL("FmSearchEngine::SearchNextImpl() : die Methoden-Listbox duerfte nur 4 Eintraege enthalten ...");
1025 [ # # ][ # # ]: 0 : }
1026 : : }
1027 : : }
1028 : :
1029 : : // fuer Arbeit auf Feldliste
1030 : 0 : FieldCollectionIterator iterBegin = m_arrUsedFields.begin();
1031 : 0 : FieldCollectionIterator iterEnd = m_arrUsedFields.end();
1032 : 0 : FieldCollectionIterator iterFieldCheck;
1033 : :
1034 : : sal_Int32 nFieldPos;
1035 : :
1036 [ # # ]: 0 : if (HasPreviousLoc())
1037 : : {
1038 : : DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()),
1039 : : "FmSearchEngine::SearchNextImpl : ungueltige Position !");
1040 : 0 : iterFieldCheck = m_iterPreviousLocField;
1041 : : // im Feld nach (oder vor) der letzten Fundstelle weitermachen
1042 [ # # ]: 0 : nFieldPos = iterFieldCheck - iterBegin;
1043 [ # # ]: 0 : MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1044 : : }
1045 : : else
1046 : : {
1047 [ # # ]: 0 : if (m_bForward)
1048 : 0 : iterFieldCheck = iterBegin;
1049 : : else
1050 : : {
1051 : 0 : iterFieldCheck = iterEnd;
1052 [ # # ]: 0 : --iterFieldCheck;
1053 : : }
1054 [ # # ]: 0 : nFieldPos = iterFieldCheck - iterBegin;
1055 : : }
1056 : :
1057 [ # # ]: 0 : PropagateProgress(sal_True);
1058 : : SEARCH_RESULT srResult;
1059 [ # # ]: 0 : if (m_eSearchForType != SEARCHFOR_STRING)
1060 [ # # ]: 0 : srResult = SearchSpecial(m_eSearchForType == SEARCHFOR_NULL, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1061 [ # # ][ # # ]: 0 : else if (!m_bRegular && !m_bLevenshtein)
1062 [ # # ]: 0 : srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1063 : : else
1064 [ # # ]: 0 : srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1065 : :
1066 : 0 : m_srResult = srResult;
1067 : :
1068 [ # # ]: 0 : if (SR_ERROR == m_srResult)
1069 : 0 : return;
1070 : :
1071 : : // gefunden ?
1072 [ # # ]: 0 : if (SR_FOUND == m_srResult)
1073 : : {
1074 : : // die Pos merken
1075 [ # # ]: 0 : try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
1076 [ # # ]: 0 : catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
1077 : 0 : m_iterPreviousLocField = iterFieldCheck;
1078 : : }
1079 : : else
1080 : : // die "letzte Fundstelle" invalidieren
1081 [ # # ][ # # ]: 0 : InvalidatePreviousLoc();
1082 : : }
1083 : :
1084 : : //------------------------------------------------------------------------
1085 : 0 : IMPL_LINK(FmSearchEngine, OnSearchTerminated, FmSearchThread*, /*pThread*/)
1086 : : {
1087 [ # # ][ # # ]: 0 : if (!m_aProgressHandler.IsSet())
1088 : 0 : return 0L;
1089 : :
1090 : 0 : FmSearchProgress aProgress;
1091 : : try
1092 : : {
1093 [ # # # # : 0 : switch (m_srResult)
# ]
1094 : : {
1095 : : case SR_ERROR :
1096 : 0 : aProgress.aSearchState = FmSearchProgress::STATE_ERROR;
1097 : 0 : break;
1098 : : case SR_FOUND :
1099 : 0 : aProgress.aSearchState = FmSearchProgress::STATE_SUCCESSFULL;
1100 : 0 : aProgress.aBookmark = m_aPreviousLocBookmark;
1101 [ # # # # ]: 0 : aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin();
1102 : 0 : break;
1103 : : case SR_NOTFOUND :
1104 : 0 : aProgress.aSearchState = FmSearchProgress::STATE_NOTHINGFOUND;
1105 [ # # ]: 0 : aProgress.aBookmark = m_xSearchCursor.getBookmark();
1106 : 0 : break;
1107 : : case SR_CANCELED :
1108 : 0 : aProgress.aSearchState = FmSearchProgress::STATE_CANCELED;
1109 [ # # ]: 0 : aProgress.aBookmark = m_xSearchCursor.getBookmark();
1110 : 0 : break;
1111 : : }
1112 [ # # ]: 0 : aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
1113 : : }
1114 [ # # ]: 0 : catch( const Exception& )
1115 : : {
1116 : : DBG_UNHANDLED_EXCEPTION();
1117 : : }
1118 : :
1119 : : // per definitionem muss der Link Thread-sicher sein (das verlange ich einfach), so dass ich mich um so etwas hier nicht kuemmern muss
1120 [ # # ]: 0 : m_aProgressHandler.Call(&aProgress);
1121 : :
1122 : 0 : m_bSearchingCurrently = sal_False;
1123 : 0 : return 0L;
1124 : : }
1125 : :
1126 : : //------------------------------------------------------------------------
1127 : 0 : IMPL_LINK(FmSearchEngine, OnNewRecordCount, void*, pCounterAsVoid)
1128 : : {
1129 [ # # ][ # # ]: 0 : if (!m_aProgressHandler.IsSet())
1130 : 0 : return 0L;
1131 : :
1132 : 0 : FmSearchProgress aProgress;
1133 : 0 : aProgress.nCurrentRecord = (sal_uIntPtr)pCounterAsVoid;
1134 : 0 : aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS_COUNTING;
1135 [ # # ]: 0 : m_aProgressHandler.Call(&aProgress);
1136 : :
1137 : 0 : return 0L;
1138 : : }
1139 : :
1140 : : //------------------------------------------------------------------------
1141 : 0 : sal_Bool FmSearchEngine::CancelRequested()
1142 : : {
1143 : 0 : m_aCancelAsynchAccess.acquire();
1144 : 0 : sal_Bool bReturn = m_bCancelAsynchRequest;
1145 : 0 : m_aCancelAsynchAccess.release();
1146 : 0 : return bReturn;
1147 : : }
1148 : :
1149 : : //------------------------------------------------------------------------
1150 : 0 : void FmSearchEngine::CancelSearch()
1151 : : {
1152 : 0 : m_aCancelAsynchAccess.acquire();
1153 : 0 : m_bCancelAsynchRequest = sal_True;
1154 : 0 : m_aCancelAsynchAccess.release();
1155 : 0 : }
1156 : :
1157 : : //------------------------------------------------------------------------
1158 : 0 : sal_Bool FmSearchEngine::SwitchToContext(const Reference< ::com::sun::star::sdbc::XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, const InterfaceArray& arrFields,
1159 : : sal_Int32 nFieldIndex)
1160 : : {
1161 : : DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !");
1162 [ # # ]: 0 : if (m_bSearchingCurrently)
1163 : 0 : return sal_False;
1164 : :
1165 [ # # ]: 0 : m_xSearchCursor = xCursor;
1166 [ # # ]: 0 : m_xOriginalIterator = xCursor;
1167 [ # # ]: 0 : m_xClonedIterator = CursorWrapper(m_xOriginalIterator, sal_True);
1168 : 0 : m_bUsingTextComponents = sal_True;
1169 : :
1170 : 0 : fillControlTexts(arrFields);
1171 : :
1172 : 0 : Init(sVisibleFields);
1173 : 0 : RebuildUsedFields(nFieldIndex, sal_True);
1174 : :
1175 : 0 : return sal_True;
1176 : : }
1177 : :
1178 : : //------------------------------------------------------------------------
1179 : 0 : void FmSearchEngine::ImplStartNextSearch()
1180 : : {
1181 : 0 : m_bCancelAsynchRequest = sal_False;
1182 : 0 : m_bSearchingCurrently = sal_True;
1183 : :
1184 [ # # ]: 0 : if (m_eMode == SM_USETHREAD)
1185 : : {
1186 [ # # ]: 0 : FmSearchThread* pSearcher = new FmSearchThread(this);
1187 : : // der loescht sich nach Beendigung selber ...
1188 : 0 : pSearcher->setTerminationHandler(LINK(this, FmSearchEngine, OnSearchTerminated));
1189 : :
1190 : 0 : pSearcher->createSuspended();
1191 : 0 : pSearcher->setPriority(osl_Thread_PriorityLowest);
1192 : 0 : pSearcher->resume();
1193 : : }
1194 : : else
1195 : : {
1196 : 0 : SearchNextImpl();
1197 [ # # ]: 0 : LINK(this, FmSearchEngine, OnSearchTerminated).Call(NULL);
1198 : : }
1199 : 0 : }
1200 : :
1201 : : //------------------------------------------------------------------------
1202 : 0 : void FmSearchEngine::SearchNext(const ::rtl::OUString& strExpression)
1203 : : {
1204 : 0 : m_strSearchExpression = strExpression;
1205 : 0 : m_eSearchForType = SEARCHFOR_STRING;
1206 : 0 : ImplStartNextSearch();
1207 : 0 : }
1208 : :
1209 : : //------------------------------------------------------------------------
1210 : 0 : void FmSearchEngine::SearchNextSpecial(sal_Bool _bSearchForNull)
1211 : : {
1212 [ # # ]: 0 : m_eSearchForType = _bSearchForNull ? SEARCHFOR_NULL : SEARCHFOR_NOTNULL;
1213 : 0 : ImplStartNextSearch();
1214 : 0 : }
1215 : :
1216 : : //------------------------------------------------------------------------
1217 : 0 : void FmSearchEngine::StartOver(const ::rtl::OUString& strExpression)
1218 : : {
1219 : : try
1220 : : {
1221 [ # # ]: 0 : if (m_bForward)
1222 [ # # ]: 0 : m_xSearchCursor.first();
1223 : : else
1224 [ # # ]: 0 : m_xSearchCursor.last();
1225 : : }
1226 : 0 : catch( const Exception& )
1227 : : {
1228 : : DBG_UNHANDLED_EXCEPTION();
1229 [ # # ]: 0 : return;
1230 : : }
1231 : :
1232 : 0 : InvalidatePreviousLoc();
1233 : 0 : SearchNext(strExpression);
1234 : : }
1235 : :
1236 : : //------------------------------------------------------------------------
1237 : 0 : void FmSearchEngine::StartOverSpecial(sal_Bool _bSearchForNull)
1238 : : {
1239 : : try
1240 : : {
1241 [ # # ]: 0 : if (m_bForward)
1242 [ # # ]: 0 : m_xSearchCursor.first();
1243 : : else
1244 [ # # ]: 0 : m_xSearchCursor.last();
1245 : : }
1246 : 0 : catch( const Exception& )
1247 : : {
1248 : : DBG_UNHANDLED_EXCEPTION();
1249 [ # # ]: 0 : return;
1250 : : }
1251 : :
1252 : 0 : InvalidatePreviousLoc();
1253 : 0 : SearchNextSpecial(_bSearchForNull);
1254 : : }
1255 : :
1256 : : //------------------------------------------------------------------------
1257 : 0 : void FmSearchEngine::InvalidatePreviousLoc()
1258 : : {
1259 : 0 : m_aPreviousLocBookmark.setValue(0,getVoidCppuType());
1260 : 0 : m_iterPreviousLocField = m_arrUsedFields.end();
1261 : 0 : }
1262 : :
1263 : : //------------------------------------------------------------------------
1264 : 0 : void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, sal_Bool bForce)
1265 : : {
1266 [ # # ][ # # ]: 0 : if (!bForce && (nFieldIndex == m_nCurrentFieldIndex))
1267 : 0 : return;
1268 : : // (da ich keinen Wechsel des Iterators von aussen zulasse, heisst selber ::com::sun::star::sdbcx::Index auch immer selbe Spalte, also habe ich nix zu tun)
1269 : :
1270 : : DBG_ASSERT((nFieldIndex == -1) ||
1271 : : ((nFieldIndex >= 0) &&
1272 : : (static_cast<size_t>(nFieldIndex) < m_arrFieldMapping.size())),
1273 : : "FmSearchEngine::RebuildUsedFields : nFieldIndex is invalid!");
1274 : : // alle Felder, die ich durchsuchen muss, einsammeln
1275 : 0 : m_arrUsedFields.clear();
1276 [ # # ]: 0 : if (nFieldIndex == -1)
1277 : : {
1278 : 0 : Reference< ::com::sun::star::container::XIndexAccess > xFields;
1279 [ # # ]: 0 : for (size_t i=0; i<m_arrFieldMapping.size(); ++i)
1280 : : {
1281 [ # # ]: 0 : Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1282 : : DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1283 [ # # ][ # # ]: 0 : xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
[ # # ][ # # ]
1284 [ # # ][ # # ]: 0 : BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[i]);
1285 : 0 : }
1286 : : }
1287 : : else
1288 : : {
1289 : 0 : Reference< ::com::sun::star::container::XIndexAccess > xFields;
1290 [ # # ]: 0 : Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1291 : : DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1292 [ # # ][ # # ]: 0 : xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
[ # # ][ # # ]
1293 [ # # ][ # # ]: 0 : BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[static_cast< size_t >(nFieldIndex)]);
1294 : : }
1295 : :
1296 : 0 : m_nCurrentFieldIndex = nFieldIndex;
1297 : : // und natuerlich beginne ich die naechste Suche wieder jungfraeulich
1298 : 0 : InvalidatePreviousLoc();
1299 : : }
1300 : :
1301 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|