bump product version to 4.1.6.2
[LibreOffice.git] / svx / source / form / fmsrcimp.cxx
blob2e393f0fdc08ef0bb108c482e4e62271f5f6bce3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/strbuf.hxx>
22 #include "svx/fmresids.hrc"
23 #include "svx/fmtools.hxx"
24 #include "svx/fmsrccfg.hxx"
25 #include <tools/debug.hxx>
26 #include <tools/diagnose_ex.h>
27 #include <tools/wldcrd.hxx>
28 #include <vcl/msgbox.hxx>
29 #include <tools/shl.hxx>
30 #include <svx/dialmgr.hxx>
31 #include <vcl/svapp.hxx>
32 #include <unotools/textsearch.hxx>
33 #include <com/sun/star/util/SearchOptions.hpp>
34 #include <com/sun/star/util/SearchAlgorithms.hpp>
35 #include <com/sun/star/util/SearchResult.hpp>
36 #include <com/sun/star/util/SearchFlags.hpp>
37 #include <com/sun/star/lang/Locale.hpp>
38 #include <com/sun/star/i18n/TransliterationModules.hpp>
39 #include <com/sun/star/i18n/CollatorOptions.hpp>
41 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
42 #include <com/sun/star/util/NumberFormatter.hpp>
43 #include <com/sun/star/util/NumberFormat.hpp>
44 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
45 #include <com/sun/star/util/XNumberFormats.hpp>
46 #include <comphelper/processfactory.hxx>
48 #include "fmprop.hrc"
49 #include "fmservs.hxx"
50 #include "svx/fmsrcimp.hxx"
51 #include <svx/fmsearch.hxx>
53 #include <comphelper/numbers.hxx>
54 #include <unotools/syslocale.hxx>
56 #define EQUAL_BOOKMARKS(a, b) a == b
58 #define IFACECAST(c) ((const Reference< XInterface >&)c)
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::util;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::sdbc;
64 using namespace ::com::sun::star::i18n;
65 using namespace ::com::sun::star::beans;
66 using namespace ::svxform;
69 //========================================================================
70 // = FmSearchThread
71 //------------------------------------------------------------------------
72 void FmSearchThread::run()
74 m_pEngine->SearchNextImpl();
77 //------------------------------------------------------------------------
78 void FmSearchThread::onTerminated()
80 if (m_aTerminationHdl.IsSet())
81 m_aTerminationHdl.Call(this);
82 delete this;
85 //========================================================================
86 // = FmRecordCountListener
88 // SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject);
90 DBG_NAME(FmRecordCountListener);
91 //------------------------------------------------------------------------
92 FmRecordCountListener::FmRecordCountListener(const Reference< ::com::sun::star::sdbc::XResultSet > & dbcCursor)
94 DBG_CTOR(FmRecordCountListener,NULL);
96 m_xListening = Reference< ::com::sun::star::beans::XPropertySet > (dbcCursor, UNO_QUERY);
97 if (!m_xListening.is())
98 return;
100 if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL)))
102 m_xListening = NULL;
103 // there's nothing to do as the record count is already known
104 return;
107 m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
110 //------------------------------------------------------------------------
111 Link FmRecordCountListener::SetPropChangeHandler(const Link& lnk)
113 Link lnkReturn = m_lnkWhoWantsToKnow;
114 m_lnkWhoWantsToKnow = lnk;
116 if (m_xListening.is())
117 NotifyCurrentCount();
119 return lnkReturn;
122 //------------------------------------------------------------------------
123 FmRecordCountListener::~FmRecordCountListener()
126 DBG_DTOR(FmRecordCountListener,NULL);
129 //------------------------------------------------------------------------
130 void FmRecordCountListener::DisConnect()
132 if(m_xListening.is())
133 m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
134 m_xListening = NULL;
137 //------------------------------------------------------------------------
138 void SAL_CALL FmRecordCountListener::disposing(const ::com::sun::star::lang::EventObject& /*Source*/) throw( RuntimeException )
140 DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !");
141 DisConnect();
144 //------------------------------------------------------------------------
145 void FmRecordCountListener::NotifyCurrentCount()
147 if (m_lnkWhoWantsToKnow.IsSet())
149 DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?");
150 void* pTheCount = (void*)(sal_IntPtr)::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT));
151 m_lnkWhoWantsToKnow.Call(pTheCount);
155 //------------------------------------------------------------------------
156 void FmRecordCountListener::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& /*evt*/) throw(::com::sun::star::uno::RuntimeException)
158 NotifyCurrentCount();
161 //========================================================================
162 // FmSearchEngine - local classes
163 //------------------------------------------------------------------------
164 SimpleTextWrapper::SimpleTextWrapper(const Reference< ::com::sun::star::awt::XTextComponent > & _xText)
165 :ControlTextWrapper(_xText.get())
166 ,m_xText(_xText)
168 DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !");
171 //------------------------------------------------------------------------
172 OUString SimpleTextWrapper::getCurrentText() const
174 return m_xText->getText();
177 //------------------------------------------------------------------------
178 ListBoxWrapper::ListBoxWrapper(const Reference< ::com::sun::star::awt::XListBox > & _xBox)
179 :ControlTextWrapper(_xBox.get())
180 ,m_xBox(_xBox)
182 DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !");
185 //------------------------------------------------------------------------
186 OUString ListBoxWrapper::getCurrentText() const
188 return m_xBox->getSelectedItem();
191 //------------------------------------------------------------------------
192 CheckBoxWrapper::CheckBoxWrapper(const Reference< ::com::sun::star::awt::XCheckBox > & _xBox)
193 :ControlTextWrapper(_xBox.get())
194 ,m_xBox(_xBox)
196 DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !");
199 //------------------------------------------------------------------------
200 OUString CheckBoxWrapper::getCurrentText() const
202 switch ((TriState)m_xBox->getState())
204 case STATE_NOCHECK: return OUString("0");
205 case STATE_CHECK: return OUString("1");
206 default: break;
208 return OUString();
211 //========================================================================
212 // = FmSearchEngine
213 //------------------------------------------------------------------------
214 sal_Bool FmSearchEngine::MoveCursor()
216 sal_Bool bSuccess = sal_True;
219 if (m_bForward)
220 if (m_xSearchCursor.isLast())
221 m_xSearchCursor.first();
222 else
223 m_xSearchCursor.next();
224 else
225 if (m_xSearchCursor.isFirst())
227 FmRecordCountListener* prclListener = new FmRecordCountListener(m_xSearchCursor);
228 prclListener->acquire();
229 prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount));
231 m_xSearchCursor.last();
233 prclListener->DisConnect();
234 prclListener->release();
236 else
237 m_xSearchCursor.previous();
239 catch(::com::sun::star::sdbc::SQLException const& e)
241 #if OSL_DEBUG_LEVEL > 0
242 OStringBuffer sDebugMessage(RTL_CONSTASCII_STRINGPARAM(
243 "FmSearchEngine::MoveCursor : catched a DatabaseException ("));
244 sDebugMessage.append(OUStringToOString(e.SQLState, RTL_TEXTENCODING_ASCII_US));
245 sDebugMessage.append(RTL_CONSTASCII_STRINGPARAM(") !"));
246 OSL_FAIL(sDebugMessage.getStr());
247 #else
248 (void)e;
249 #endif
250 bSuccess = sal_False;
252 catch(Exception const& e)
254 #if OSL_DEBUG_LEVEL > 0
255 OStringBuffer sDebugMessage(RTL_CONSTASCII_STRINGPARAM(
256 "FmSearchEngine::MoveCursor : catched an Exception ("));
257 sDebugMessage.append(OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US));
258 sDebugMessage.append(RTL_CONSTASCII_STRINGPARAM(") !"));
259 OSL_FAIL(sDebugMessage.getStr());
260 #else
261 (void)e;
262 #endif
263 bSuccess = sal_False;
265 catch(...)
267 OSL_FAIL("FmSearchEngine::MoveCursor : catched an unknown Exception !");
268 bSuccess = sal_False;
271 return bSuccess;
274 //------------------------------------------------------------------------
275 sal_Bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollectionIterator& iter, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
277 sal_Bool bSuccess(sal_True);
278 if (m_bForward)
280 ++iter;
281 ++nPos;
282 if (iter == iterEnd)
284 bSuccess = MoveCursor();
285 iter = iterBegin;
286 nPos = 0;
288 } else
290 if (iter == iterBegin)
292 bSuccess = MoveCursor();
293 iter = iterEnd;
294 nPos = iter-iterBegin;
296 --iter;
297 --nPos;
299 return bSuccess;
302 //------------------------------------------------------------------------
303 void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< ::com::sun::star::container::XIndexAccess > & xAllFields, sal_Int32 nField)
305 DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ),
306 "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" );
308 // das Feld selber
309 Reference< XInterface > xCurrentField;
310 xAllFields->getByIndex(nField) >>= xCurrentField;
312 // von dem weiss ich jetzt, dass es den DatabaseRecord-Service unterstuetzt (hoffe ich)
313 // fuer den FormatKey und den Typ brauche ich das PropertySet
314 Reference< ::com::sun::star::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY);
316 // die FieldInfo dazu aufbauen
317 FieldInfo fiCurrent;
318 fiCurrent.xContents = Reference< ::com::sun::star::sdb::XColumn > (xCurrentField, UNO_QUERY);
319 fiCurrent.nFormatKey = ::comphelper::getINT32(xProperties->getPropertyValue(FM_PROP_FORMATKEY));
320 fiCurrent.bDoubleHandling = sal_False;
321 if (m_xFormatSupplier.is())
323 Reference< ::com::sun::star::util::XNumberFormats > xNumberFormats(m_xFormatSupplier->getNumberFormats());
325 sal_Int16 nFormatType = ::comphelper::getNumberFormatType(xNumberFormats, fiCurrent.nFormatKey) & ~((sal_Int16)::com::sun::star::util::NumberFormat::DEFINED);
326 fiCurrent.bDoubleHandling = (nFormatType != ::com::sun::star::util::NumberFormat::TEXT);
329 // und merken
330 m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent);
333 //------------------------------------------------------------------------
334 OUString FmSearchEngine::FormatField(const FieldInfo& rField)
336 DBG_ASSERT(!m_bUsingTextComponents, "FmSearchEngine::FormatField : im UsingTextComponents-Mode bitte FormatField(sal_Int32) benutzen !");
338 if (!m_xFormatter.is())
339 return OUString();
340 // sonst werden Datumsflder zum Beispiel zu irgendeinem Default-Wert formatiert
342 OUString sReturn;
345 if (rField.bDoubleHandling)
347 double fValue = rField.xContents->getDouble();
348 if (!rField.xContents->wasNull())
349 sReturn = m_xFormatter->convertNumberToString(rField.nFormatKey, fValue);
351 else
353 OUString sValue = rField.xContents->getString();
354 if (!rField.xContents->wasNull())
355 sReturn = m_xFormatter->formatString(rField.nFormatKey, sValue);
358 catch(...)
363 return sReturn;
366 //------------------------------------------------------------------------
367 OUString FmSearchEngine::FormatField(sal_Int32 nWhich)
369 if (m_bUsingTextComponents)
371 DBG_ASSERT((sal_uInt32)nWhich < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !");
372 DBG_ASSERT(m_aControlTexts[nWhich] != NULL, "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !");
373 DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !");
375 if (m_nCurrentFieldIndex != -1)
377 DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
378 // analoge Situation wie unten
379 nWhich = m_nCurrentFieldIndex;
382 DBG_ASSERT((nWhich >= 0) && ((sal_uInt32)nWhich < m_aControlTexts.size()),
383 "FmSearchEngine::FormatField : invalid argument nWhich !");
384 return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText();
386 else
388 if (m_nCurrentFieldIndex != -1)
390 DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
391 // ich bin im single-field-modus, da ist auch die richtige Feld-Nummer erlaubt, obwohl dann der richtige ::com::sun::star::sdbcx::Index
392 // fuer meinen Array-Zugriff natuerlich 0 ist
393 nWhich = 0;
396 DBG_ASSERT((nWhich>=0) && (nWhich < (m_arrUsedFields.end() - m_arrUsedFields.begin())),
397 "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
398 return FormatField(m_arrUsedFields[nWhich]);
402 //------------------------------------------------------------------------
403 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchSpecial(sal_Bool _bSearchForNull, sal_Int32& nFieldPos,
404 FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
406 // die Startposition merken
407 Any aStartMark;
408 try { aStartMark = m_xSearchCursor.getBookmark(); }
409 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
410 FieldCollectionIterator iterInitialField = iterFieldLoop;
412 // --------------------------------------------------------------
413 sal_Bool bFound(sal_False);
414 sal_Bool bMovedAround(sal_False);
417 if (m_eMode == SM_ALLOWSCHEDULE)
419 Application::Reschedule();
420 Application::Reschedule();
421 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
422 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
423 // or anything like that. So within each loop we create one user event and handle one user event (and no
424 // paintings and these), so the office seems to be frozen while searching.
425 // FS - 70226 - 02.12.99
428 // der aktuell zu vergleichende Inhalt
429 iterFieldLoop->xContents->getString(); // needed for wasNull
430 bFound = _bSearchForNull == iterFieldLoop->xContents->wasNull();
431 if (bFound)
432 break;
434 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
435 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
436 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
437 // das selbe bestimmt wieder schief geht, also Abbruch
438 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
439 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
440 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
441 m_iterPreviousLocField = iterFieldLoop;
442 // und wech
443 return SR_ERROR;
446 Any aCurrentBookmark;
447 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
448 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
450 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
452 if (nFieldPos == 0)
453 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
454 PropagateProgress(bMovedAround);
455 // if we moved to the starting position we don't have to propagate an 'overflow' message
456 // FS - 07.12.99 - 68530
458 // abbrechen gefordert ?
459 if (CancelRequested())
460 return SR_CANCELED;
462 } while (!bMovedAround);
464 return bFound ? SR_FOUND : SR_NOTFOUND;
467 //------------------------------------------------------------------------
468 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchWildcard(const OUString& strExpression, sal_Int32& nFieldPos,
469 FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
471 // die Startposition merken
472 Any aStartMark;
473 try { aStartMark = m_xSearchCursor.getBookmark(); }
474 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
475 FieldCollectionIterator iterInitialField = iterFieldLoop;
477 WildCard aSearchExpression(strExpression);
479 // --------------------------------------------------------------
480 sal_Bool bFound(sal_False);
481 sal_Bool bMovedAround(sal_False);
484 if (m_eMode == SM_ALLOWSCHEDULE)
486 Application::Reschedule();
487 Application::Reschedule();
488 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
489 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
490 // or anything like that. So within each loop we create one user event and hanel one user event (and no
491 // paintings and these), so the office seems to be frozen while searching.
492 // FS - 70226 - 02.12.99
495 // der aktuell zu vergleichende Inhalt
496 OUString sCurrentCheck;
497 if (m_bFormatter)
498 sCurrentCheck = FormatField(nFieldPos);
499 else
500 sCurrentCheck = iterFieldLoop->xContents->getString();
502 if (!GetCaseSensitive())
503 // norm the string
504 sCurrentCheck = m_aCharacterClassficator.lowercase(sCurrentCheck);
506 // jetzt ist der Test einfach ...
507 bFound = aSearchExpression.Matches(sCurrentCheck);
509 if (bFound)
510 break;
512 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
513 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
514 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
515 // das selbe bestimmt wieder schief geht, also Abbruch
516 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
517 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
518 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
519 m_iterPreviousLocField = iterFieldLoop;
520 // und wech
521 return SR_ERROR;
524 Any aCurrentBookmark;
525 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
526 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
528 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
530 if (nFieldPos == 0)
531 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
532 PropagateProgress(bMovedAround);
533 // if we moved to the starting position we don't have to propagate an 'overflow' message
534 // FS - 07.12.99 - 68530
536 // abbrechen gefordert ?
537 if (CancelRequested())
538 return SR_CANCELED;
540 } while (!bMovedAround);
542 return bFound ? SR_FOUND : SR_NOTFOUND;
545 //------------------------------------------------------------------------
546 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchRegularApprox(const OUString& strExpression, sal_Int32& nFieldPos,
547 FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
549 DBG_ASSERT(m_bLevenshtein || m_bRegular,
550 "FmSearchEngine::SearchRegularApprox : ungueltiger Suchmodus !");
551 DBG_ASSERT(!m_bLevenshtein || !m_bRegular,
552 "FmSearchEngine::SearchRegularApprox : kann nicht nach regulaeren Ausdruecken und nach Aehnlichkeiten gleichzeitig suchen !");
554 // Startposition merken
555 Any aStartMark;
556 try { aStartMark = m_xSearchCursor.getBookmark(); }
557 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
558 FieldCollectionIterator iterInitialField = iterFieldLoop;
560 // Parameter sammeln
561 SearchOptions aParam;
562 aParam.algorithmType = m_bRegular ? SearchAlgorithms_REGEXP : SearchAlgorithms_APPROXIMATE;
563 aParam.searchFlag = 0;
564 aParam.transliterateFlags = GetTransliterationFlags();
565 if ( !GetTransliteration() )
566 { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH
567 aParam.transliterateFlags &= TransliterationModules_IGNORE_CASE | TransliterationModules_IGNORE_WIDTH;
569 if (m_bLevenshtein)
571 if (m_bLevRelaxed)
572 aParam.searchFlag |= SearchFlags::LEV_RELAXED;
573 aParam.changedChars = m_nLevOther;
574 aParam.deletedChars = m_nLevShorter;
575 aParam.insertedChars = m_nLevLonger;
577 aParam.searchString = strExpression;
578 aParam.Locale = SvtSysLocale().GetLanguageTag().getLocale();
579 ::utl::TextSearch aLocalEngine(aParam);
581 // --------------------------------------------------------------
582 bool bFound = false;
583 sal_Bool bMovedAround(sal_False);
586 if (m_eMode == SM_ALLOWSCHEDULE)
588 Application::Reschedule();
589 Application::Reschedule();
590 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
591 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
592 // or anything like that. So within each loop we create one user event and handle one user event (and no
593 // paintings and these), so the office seems to be frozen while searching.
594 // FS - 70226 - 02.12.99
597 // der aktuell zu vergleichende Inhalt
598 OUString sCurrentCheck;
599 if (m_bFormatter)
600 sCurrentCheck = FormatField(nFieldPos);
601 else
602 sCurrentCheck = iterFieldLoop->xContents->getString();
604 // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it)
606 xub_StrLen nStart = 0, nEnd = (xub_StrLen)sCurrentCheck.getLength();
607 bFound = aLocalEngine.SearchFrwrd(sCurrentCheck, &nStart, &nEnd);
608 // das heisst hier 'forward' aber das bezieht sich nur auf die Suche innerhalb von sCurrentCheck, hat also mit
609 // der Richtung meines Datensatz-Durchwanderns nix zu tun (darum kuemmert sich MoveField)
611 // checken, ob die Position stimmt
612 if (bFound)
614 switch (m_nPosition)
616 case MATCHING_WHOLETEXT :
617 if (nEnd != sCurrentCheck.getLength())
619 bFound = false;
620 break;
622 // laeuft in den naechsten Case rein !
623 case MATCHING_BEGINNING :
624 if (nStart != 0)
625 bFound = false;
626 break;
627 case MATCHING_END :
628 if (nEnd != sCurrentCheck.getLength())
629 bFound = false;
630 break;
634 if (bFound) // immer noch ?
635 break;
637 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
638 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
639 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
640 // das selbe bestimmt wieder schief geht, also Abbruch (ohne Fehlermeldung, von der erwarte ich, dass sie im Move
641 // angezeigt wurde)
642 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
643 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
644 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
645 m_iterPreviousLocField = iterFieldLoop;
646 // und wech
647 return SR_ERROR;
650 Any aCurrentBookmark;
651 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
652 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
653 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
655 if (nFieldPos == 0)
656 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
657 PropagateProgress(bMovedAround);
658 // if we moved to the starting position we don't have to propagate an 'overflow' message
659 // FS - 07.12.99 - 68530
661 // abbrechen gefordert ?
662 if (CancelRequested())
663 return SR_CANCELED;
665 } while (!bMovedAround);
667 return bFound ? SR_FOUND : SR_NOTFOUND;
671 DBG_NAME(FmSearchEngine);
672 //------------------------------------------------------------------------
673 FmSearchEngine::FmSearchEngine(const Reference< XComponentContext >& _rxContext,
674 const Reference< XResultSet > & xCursor, const OUString& sVisibleFields,
675 const Reference< XNumberFormatsSupplier > & xFormatSupplier, FMSEARCH_MODE eMode)
677 :m_xSearchCursor(xCursor)
678 ,m_xFormatSupplier(xFormatSupplier)
679 ,m_aCharacterClassficator( _rxContext, SvtSysLocale().GetLanguageTag() )
680 ,m_aStringCompare( _rxContext )
681 ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
682 ,m_bUsingTextComponents(sal_False)
683 ,m_eSearchForType(SEARCHFOR_STRING)
684 ,m_srResult(SR_FOUND)
685 ,m_bSearchingCurrently(sal_False)
686 ,m_bCancelAsynchRequest(sal_False)
687 ,m_eMode(eMode)
688 ,m_bFormatter(sal_False)
689 ,m_bForward(sal_False)
690 ,m_bWildcard(sal_False)
691 ,m_bRegular(sal_False)
692 ,m_bLevenshtein(sal_False)
693 ,m_bTransliteration(sal_False)
694 ,m_bLevRelaxed(sal_False)
695 ,m_nLevOther(0)
696 ,m_nLevShorter(0)
697 ,m_nLevLonger(0)
698 ,m_nPosition(MATCHING_ANYWHERE)
699 ,m_nTransliterationFlags(0)
701 DBG_CTOR(FmSearchEngine,NULL);
703 m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(
704 ::com::sun::star::util::NumberFormatter::create( ::comphelper::getProcessComponentContext() ),
705 UNO_QUERY_THROW);
706 m_xFormatter->attachNumberFormatsSupplier(m_xFormatSupplier);
708 Init(sVisibleFields);
711 //------------------------------------------------------------------------
712 FmSearchEngine::FmSearchEngine(const Reference< XComponentContext >& _rxContext,
713 const Reference< XResultSet > & xCursor, const OUString& sVisibleFields,
714 const InterfaceArray& arrFields, FMSEARCH_MODE eMode)
715 :m_xSearchCursor(xCursor)
716 ,m_aCharacterClassficator( _rxContext, SvtSysLocale().GetLanguageTag() )
717 ,m_aStringCompare( _rxContext )
718 ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
719 ,m_bUsingTextComponents(sal_True)
720 ,m_xOriginalIterator(xCursor)
721 ,m_xClonedIterator(m_xOriginalIterator, sal_True)
722 ,m_eSearchForType(SEARCHFOR_STRING)
723 ,m_srResult(SR_FOUND)
724 ,m_bSearchingCurrently(sal_False)
725 ,m_bCancelAsynchRequest(sal_False)
726 ,m_eMode(eMode)
727 ,m_bFormatter(sal_True) // das muss konsistent sein mit m_xSearchCursor, der i.A. == m_xOriginalIterator ist
728 ,m_bForward(sal_False)
729 ,m_bWildcard(sal_False)
730 ,m_bRegular(sal_False)
731 ,m_bLevenshtein(sal_False)
732 ,m_bTransliteration(sal_False)
733 ,m_bLevRelaxed(sal_False)
734 ,m_nLevOther(0)
735 ,m_nLevShorter(0)
736 ,m_nLevLonger(0)
737 ,m_nPosition(MATCHING_ANYWHERE)
738 ,m_nTransliterationFlags(0)
740 DBG_CTOR(FmSearchEngine,NULL);
742 fillControlTexts(arrFields);
743 Init(sVisibleFields);
746 //------------------------------------------------------------------------
747 FmSearchEngine::~FmSearchEngine()
749 clearControlTexts();
751 DBG_DTOR(FmSearchEngine,NULL);
754 //------------------------------------------------------------------------
755 void FmSearchEngine::SetIgnoreWidthCJK(sal_Bool bSet)
757 if (bSet)
758 m_nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH;
759 else
760 m_nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH;
763 //------------------------------------------------------------------------
764 sal_Bool FmSearchEngine::GetIgnoreWidthCJK() const
766 return 0 != (m_nTransliterationFlags & TransliterationModules_IGNORE_WIDTH);
769 //------------------------------------------------------------------------
770 void FmSearchEngine::SetCaseSensitive(sal_Bool bSet)
772 if (bSet)
773 m_nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE;
774 else
775 m_nTransliterationFlags |= TransliterationModules_IGNORE_CASE;
778 //------------------------------------------------------------------------
779 sal_Bool FmSearchEngine::GetCaseSensitive() const
781 return 0 == (m_nTransliterationFlags & TransliterationModules_IGNORE_CASE);
784 //------------------------------------------------------------------------
785 void FmSearchEngine::clearControlTexts()
787 for ( ControlTextSuppliersIterator aIter = m_aControlTexts.begin();
788 aIter < m_aControlTexts.end();
789 ++aIter
792 delete *aIter;
794 m_aControlTexts.clear();
797 //------------------------------------------------------------------------
798 void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields)
800 clearControlTexts();
801 Reference< XInterface > xCurrent;
802 for (sal_uInt32 i=0; i<arrFields.size(); ++i)
804 xCurrent = arrFields.at(i);
805 DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !");
806 // check which type of control this is
807 Reference< ::com::sun::star::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY);
808 if (xAsText.is())
810 m_aControlTexts.insert(m_aControlTexts.end(), new SimpleTextWrapper(xAsText));
811 continue;
814 Reference< ::com::sun::star::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY);
815 if (xAsListBox.is())
817 m_aControlTexts.insert(m_aControlTexts.end(), new ListBoxWrapper(xAsListBox));
818 continue;
821 Reference< ::com::sun::star::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY);
822 DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !");
823 // we don't have any more options ...
824 m_aControlTexts.insert(m_aControlTexts.end(), new CheckBoxWrapper(xAsCheckBox));
828 //------------------------------------------------------------------------
829 void FmSearchEngine::Init(const OUString& sVisibleFields)
831 // analyze the fields
832 // additionally, create the mapping: because the list of used columns can be shorter than the list
833 // of columns of the cursor, we need a mapping: "used column numer n" -> "cursor column m"
834 m_arrFieldMapping.clear();
836 // important: The case of the columns does not need to be exact - for instance:
837 // - a user created a form which works on a table, for which the driver returns a column name "COLUMN"
838 // - the driver itself works case-insensitve with column names
839 // - a control in the form is bound to "column" - not the different case
840 // In such a scenario, the form and the field would work okay, but we here need to case for the different case
841 // explicitly
842 // #i8755#
844 // so first of all, check if the database handles identifiers case sensitive
845 Reference< XConnection > xConn;
846 Reference< XDatabaseMetaData > xMeta;
847 Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY );
848 if ( xCursorProps.is() )
852 xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn;
854 catch( const Exception& ) { /* silent this - will be asserted below */ }
856 if ( xConn.is() )
857 xMeta = xConn->getMetaData();
858 OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" );
860 sal_Bool bCaseSensitiveIdentifiers = sal_True; // assume case sensivity
861 if ( xMeta.is() )
862 bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers();
864 // now that we have this information, we need a collator which is able to case (in)sentively compare strings
865 m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLanguageTag().getLocale(),
866 bCaseSensitiveIdentifiers ? 0 : ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
870 // der Cursor kann mir einen Record (als PropertySet) liefern, dieser unterstuetzt den DatabaseRecord-Service
871 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
872 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !");
873 Reference< ::com::sun::star::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns();
874 Sequence< OUString > seqFieldNames = xAllFieldNames->getElementNames();
875 OUString* pFieldNames = seqFieldNames.getArray();
878 OUString sCurrentField;
879 OUString sVis(sVisibleFields.getStr());
880 sal_Int32 nIndex = 0;
883 sCurrentField = sVis.getToken(0, ';' , nIndex);
885 // in der Feld-Sammlung suchen
886 sal_Int32 nFoundIndex = -1;
887 for (sal_Int32 j=0; j<seqFieldNames.getLength(); ++j, ++pFieldNames)
889 if ( 0 == m_aStringCompare.compareString( *pFieldNames, sCurrentField ) )
891 nFoundIndex = j;
892 break;
895 // set the field selection back to the first
896 pFieldNames = seqFieldNames.getArray();
897 DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Invalid field name were given !");
898 m_arrFieldMapping.push_back(nFoundIndex);
900 while ( nIndex >= 0 );
902 catch (const Exception&)
904 OSL_FAIL("Exception occurred!");
909 //------------------------------------------------------------------------
910 void FmSearchEngine::SetFormatterUsing(sal_Bool bSet)
912 if (m_bFormatter == bSet)
913 return;
914 m_bFormatter = bSet;
916 if (m_bUsingTextComponents)
918 // ich benutzte keinen Formatter, sondern TextComponents -> der SearchIterator muss angepasst werden
921 if (m_bFormatter)
923 DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
924 m_xSearchCursor = m_xOriginalIterator;
925 m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark());
926 // damit ich mit dem neuen Iterator wirklich dort weitermache, wo ich vorher aufgehoert habe
928 else
930 DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
931 m_xSearchCursor = m_xClonedIterator;
932 m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark());
935 catch( const Exception& )
937 DBG_UNHANDLED_EXCEPTION();
940 // ich muss die Fields neu binden, da der Textaustausch eventuell ueber diese Fields erfolgt und sich der unterliegende Cursor
941 // geaendert hat
942 RebuildUsedFields(m_nCurrentFieldIndex, sal_True);
944 else
945 InvalidatePreviousLoc();
948 //------------------------------------------------------------------------
949 void FmSearchEngine::PropagateProgress(sal_Bool _bDontPropagateOverflow)
951 if (m_aProgressHandler.IsSet())
953 FmSearchProgress aProgress;
956 aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS;
957 aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
958 if (m_bForward)
959 aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst();
960 else
961 aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast();
963 catch( const Exception& )
965 DBG_UNHANDLED_EXCEPTION();
968 m_aProgressHandler.Call(&aProgress);
972 //------------------------------------------------------------------------
973 void FmSearchEngine::SearchNextImpl()
975 DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard),
976 "FmSearchEngine::SearchNextImpl : Suchparameter schliessen sich gegenseitig aus !");
978 DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : habe ungueltigen Iterator !");
980 // die Parameter der Suche
981 OUString strSearchExpression(m_strSearchExpression); // brauche ich non-const
982 if (!GetCaseSensitive())
983 // norm the string
984 strSearchExpression = m_aCharacterClassficator.lowercase(strSearchExpression);
986 if (!m_bRegular && !m_bLevenshtein)
987 { // 'normale' Suche fuehre ich auf jeden Fall ueber WildCards durch, muss aber vorher je nach Modus den OUString anpassen
989 if (!m_bWildcard)
990 { // da natuerlich in allen anderen Faellen auch * und ? im Suchstring erlaubt sind, aber nicht als WildCards zaehlen
991 // sollen, muss ich normieren
992 OUString aTmp(strSearchExpression);
993 const OUString s_sStar("\\*");
994 const OUString s_sQuotation("\\?");
995 aTmp = aTmp.replaceAll("*", s_sStar);
996 aTmp = aTmp.replaceAll("?", s_sQuotation);
997 strSearchExpression = aTmp;
999 switch (m_nPosition)
1001 case MATCHING_ANYWHERE :
1002 strSearchExpression = "*" + strSearchExpression + "*";
1003 break;
1004 case MATCHING_BEGINNING :
1005 strSearchExpression = strSearchExpression + "*";
1006 break;
1007 case MATCHING_END :
1008 strSearchExpression = "*" + strSearchExpression;
1009 break;
1010 case MATCHING_WHOLETEXT :
1011 break;
1012 default :
1013 OSL_FAIL("FmSearchEngine::SearchNextImpl() : die Methoden-Listbox duerfte nur 4 Eintraege enthalten ...");
1018 // fuer Arbeit auf Feldliste
1019 FieldCollectionIterator iterBegin = m_arrUsedFields.begin();
1020 FieldCollectionIterator iterEnd = m_arrUsedFields.end();
1021 FieldCollectionIterator iterFieldCheck;
1023 sal_Int32 nFieldPos;
1025 if (HasPreviousLoc())
1027 DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()),
1028 "FmSearchEngine::SearchNextImpl : ungueltige Position !");
1029 iterFieldCheck = m_iterPreviousLocField;
1030 // im Feld nach (oder vor) der letzten Fundstelle weitermachen
1031 nFieldPos = iterFieldCheck - iterBegin;
1032 MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1034 else
1036 if (m_bForward)
1037 iterFieldCheck = iterBegin;
1038 else
1040 iterFieldCheck = iterEnd;
1041 --iterFieldCheck;
1043 nFieldPos = iterFieldCheck - iterBegin;
1046 PropagateProgress(sal_True);
1047 SEARCH_RESULT srResult;
1048 if (m_eSearchForType != SEARCHFOR_STRING)
1049 srResult = SearchSpecial(m_eSearchForType == SEARCHFOR_NULL, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1050 else if (!m_bRegular && !m_bLevenshtein)
1051 srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1052 else
1053 srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1055 m_srResult = srResult;
1057 if (SR_ERROR == m_srResult)
1058 return;
1060 // gefunden ?
1061 if (SR_FOUND == m_srResult)
1063 // die Pos merken
1064 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
1065 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
1066 m_iterPreviousLocField = iterFieldCheck;
1068 else
1069 // die "letzte Fundstelle" invalidieren
1070 InvalidatePreviousLoc();
1073 //------------------------------------------------------------------------
1074 IMPL_LINK(FmSearchEngine, OnSearchTerminated, FmSearchThread*, /*pThread*/)
1076 if (!m_aProgressHandler.IsSet())
1077 return 0L;
1079 FmSearchProgress aProgress;
1082 switch (m_srResult)
1084 case SR_ERROR :
1085 aProgress.aSearchState = FmSearchProgress::STATE_ERROR;
1086 break;
1087 case SR_FOUND :
1088 aProgress.aSearchState = FmSearchProgress::STATE_SUCCESSFULL;
1089 aProgress.aBookmark = m_aPreviousLocBookmark;
1090 aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin();
1091 break;
1092 case SR_NOTFOUND :
1093 aProgress.aSearchState = FmSearchProgress::STATE_NOTHINGFOUND;
1094 aProgress.aBookmark = m_xSearchCursor.getBookmark();
1095 break;
1096 case SR_CANCELED :
1097 aProgress.aSearchState = FmSearchProgress::STATE_CANCELED;
1098 aProgress.aBookmark = m_xSearchCursor.getBookmark();
1099 break;
1101 aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
1103 catch( const Exception& )
1105 DBG_UNHANDLED_EXCEPTION();
1108 // per definitionem muss der Link Thread-sicher sein (das verlange ich einfach), so dass ich mich um so etwas hier nicht kuemmern muss
1109 m_aProgressHandler.Call(&aProgress);
1111 m_bSearchingCurrently = sal_False;
1112 return 0L;
1115 //------------------------------------------------------------------------
1116 IMPL_LINK(FmSearchEngine, OnNewRecordCount, void*, pCounterAsVoid)
1118 if (!m_aProgressHandler.IsSet())
1119 return 0L;
1121 FmSearchProgress aProgress;
1122 aProgress.nCurrentRecord = (sal_uIntPtr)pCounterAsVoid;
1123 aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS_COUNTING;
1124 m_aProgressHandler.Call(&aProgress);
1126 return 0L;
1129 //------------------------------------------------------------------------
1130 sal_Bool FmSearchEngine::CancelRequested()
1132 m_aCancelAsynchAccess.acquire();
1133 sal_Bool bReturn = m_bCancelAsynchRequest;
1134 m_aCancelAsynchAccess.release();
1135 return bReturn;
1138 //------------------------------------------------------------------------
1139 void FmSearchEngine::CancelSearch()
1141 m_aCancelAsynchAccess.acquire();
1142 m_bCancelAsynchRequest = sal_True;
1143 m_aCancelAsynchAccess.release();
1146 //------------------------------------------------------------------------
1147 sal_Bool FmSearchEngine::SwitchToContext(const Reference< ::com::sun::star::sdbc::XResultSet > & xCursor, const OUString& sVisibleFields, const InterfaceArray& arrFields,
1148 sal_Int32 nFieldIndex)
1150 DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !");
1151 if (m_bSearchingCurrently)
1152 return sal_False;
1154 m_xSearchCursor = xCursor;
1155 m_xOriginalIterator = xCursor;
1156 m_xClonedIterator = CursorWrapper(m_xOriginalIterator, sal_True);
1157 m_bUsingTextComponents = sal_True;
1159 fillControlTexts(arrFields);
1161 Init(sVisibleFields);
1162 RebuildUsedFields(nFieldIndex, sal_True);
1164 return sal_True;
1167 //------------------------------------------------------------------------
1168 void FmSearchEngine::ImplStartNextSearch()
1170 m_bCancelAsynchRequest = sal_False;
1171 m_bSearchingCurrently = sal_True;
1173 if (m_eMode == SM_USETHREAD)
1175 FmSearchThread* pSearcher = new FmSearchThread(this);
1176 // der loescht sich nach Beendigung selber ...
1177 pSearcher->setTerminationHandler(LINK(this, FmSearchEngine, OnSearchTerminated));
1179 pSearcher->createSuspended();
1180 pSearcher->setPriority(osl_Thread_PriorityLowest);
1181 pSearcher->resume();
1183 else
1185 SearchNextImpl();
1186 LINK(this, FmSearchEngine, OnSearchTerminated).Call(NULL);
1190 //------------------------------------------------------------------------
1191 void FmSearchEngine::SearchNext(const OUString& strExpression)
1193 m_strSearchExpression = strExpression;
1194 m_eSearchForType = SEARCHFOR_STRING;
1195 ImplStartNextSearch();
1198 //------------------------------------------------------------------------
1199 void FmSearchEngine::SearchNextSpecial(sal_Bool _bSearchForNull)
1201 m_eSearchForType = _bSearchForNull ? SEARCHFOR_NULL : SEARCHFOR_NOTNULL;
1202 ImplStartNextSearch();
1205 //------------------------------------------------------------------------
1206 void FmSearchEngine::StartOver(const OUString& strExpression)
1210 if (m_bForward)
1211 m_xSearchCursor.first();
1212 else
1213 m_xSearchCursor.last();
1215 catch( const Exception& )
1217 DBG_UNHANDLED_EXCEPTION();
1218 return;
1221 InvalidatePreviousLoc();
1222 SearchNext(strExpression);
1225 //------------------------------------------------------------------------
1226 void FmSearchEngine::StartOverSpecial(sal_Bool _bSearchForNull)
1230 if (m_bForward)
1231 m_xSearchCursor.first();
1232 else
1233 m_xSearchCursor.last();
1235 catch( const Exception& )
1237 DBG_UNHANDLED_EXCEPTION();
1238 return;
1241 InvalidatePreviousLoc();
1242 SearchNextSpecial(_bSearchForNull);
1245 //------------------------------------------------------------------------
1246 void FmSearchEngine::InvalidatePreviousLoc()
1248 m_aPreviousLocBookmark.setValue(0,getVoidCppuType());
1249 m_iterPreviousLocField = m_arrUsedFields.end();
1252 //------------------------------------------------------------------------
1253 void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, sal_Bool bForce)
1255 if (!bForce && (nFieldIndex == m_nCurrentFieldIndex))
1256 return;
1257 // (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)
1259 DBG_ASSERT((nFieldIndex == -1) ||
1260 ((nFieldIndex >= 0) &&
1261 (static_cast<size_t>(nFieldIndex) < m_arrFieldMapping.size())),
1262 "FmSearchEngine::RebuildUsedFields : nFieldIndex is invalid!");
1263 // alle Felder, die ich durchsuchen muss, einsammeln
1264 m_arrUsedFields.clear();
1265 if (nFieldIndex == -1)
1267 Reference< ::com::sun::star::container::XIndexAccess > xFields;
1268 for (size_t i=0; i<m_arrFieldMapping.size(); ++i)
1270 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1271 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1272 xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
1273 BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[i]);
1276 else
1278 Reference< ::com::sun::star::container::XIndexAccess > xFields;
1279 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1280 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1281 xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
1282 BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[static_cast< size_t >(nFieldIndex)]);
1285 m_nCurrentFieldIndex = nFieldIndex;
1286 // und natuerlich beginne ich die naechste Suche wieder jungfraeulich
1287 InvalidatePreviousLoc();
1290 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */