Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / form / fmsrcimp.cxx
blobbaf98b6c97bf17dc475a9b4d3e945b61a114e22b
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;
70 // = FmSearchThread
72 void FmSearchThread::run()
74 m_pEngine->SearchNextImpl();
78 void FmSearchThread::onTerminated()
80 if (m_aTerminationHdl.IsSet())
81 m_aTerminationHdl.Call(this);
82 delete this;
86 // = FmRecordCountListener
88 // SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject);
91 FmRecordCountListener::FmRecordCountListener(const Reference< ::com::sun::star::sdbc::XResultSet > & dbcCursor)
94 m_xListening = Reference< ::com::sun::star::beans::XPropertySet > (dbcCursor, UNO_QUERY);
95 if (!m_xListening.is())
96 return;
98 if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL)))
100 m_xListening = NULL;
101 // there's nothing to do as the record count is already known
102 return;
105 m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
109 Link FmRecordCountListener::SetPropChangeHandler(const Link& lnk)
111 Link lnkReturn = m_lnkWhoWantsToKnow;
112 m_lnkWhoWantsToKnow = lnk;
114 if (m_xListening.is())
115 NotifyCurrentCount();
117 return lnkReturn;
121 FmRecordCountListener::~FmRecordCountListener()
127 void FmRecordCountListener::DisConnect()
129 if(m_xListening.is())
130 m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
131 m_xListening = NULL;
135 void SAL_CALL FmRecordCountListener::disposing(const ::com::sun::star::lang::EventObject& /*Source*/) throw( RuntimeException, std::exception )
137 DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !");
138 DisConnect();
142 void FmRecordCountListener::NotifyCurrentCount()
144 if (m_lnkWhoWantsToKnow.IsSet())
146 DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?");
147 void* pTheCount = (void*)(sal_IntPtr)::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT));
148 m_lnkWhoWantsToKnow.Call(pTheCount);
153 void FmRecordCountListener::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& /*evt*/) throw(::com::sun::star::uno::RuntimeException, std::exception)
155 NotifyCurrentCount();
159 // FmSearchEngine - local classes
161 SimpleTextWrapper::SimpleTextWrapper(const Reference< ::com::sun::star::awt::XTextComponent > & _xText)
162 :ControlTextWrapper(_xText.get())
163 ,m_xText(_xText)
165 DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !");
169 OUString SimpleTextWrapper::getCurrentText() const
171 return m_xText->getText();
175 ListBoxWrapper::ListBoxWrapper(const Reference< ::com::sun::star::awt::XListBox > & _xBox)
176 :ControlTextWrapper(_xBox.get())
177 ,m_xBox(_xBox)
179 DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !");
183 OUString ListBoxWrapper::getCurrentText() const
185 return m_xBox->getSelectedItem();
189 CheckBoxWrapper::CheckBoxWrapper(const Reference< ::com::sun::star::awt::XCheckBox > & _xBox)
190 :ControlTextWrapper(_xBox.get())
191 ,m_xBox(_xBox)
193 DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !");
197 OUString CheckBoxWrapper::getCurrentText() const
199 switch ((TriState)m_xBox->getState())
201 case TRISTATE_FALSE: return OUString("0");
202 case TRISTATE_TRUE: return OUString("1");
203 default: break;
205 return OUString();
209 // = FmSearchEngine
211 bool FmSearchEngine::MoveCursor()
213 bool bSuccess = true;
216 if (m_bForward)
217 if (m_xSearchCursor.isLast())
218 m_xSearchCursor.first();
219 else
220 m_xSearchCursor.next();
221 else
222 if (m_xSearchCursor.isFirst())
224 FmRecordCountListener* prclListener = new FmRecordCountListener(m_xSearchCursor);
225 prclListener->acquire();
226 prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount));
228 m_xSearchCursor.last();
230 prclListener->DisConnect();
231 prclListener->release();
233 else
234 m_xSearchCursor.previous();
236 catch(::com::sun::star::sdbc::SQLException const& e)
238 #if OSL_DEBUG_LEVEL > 0
239 OStringBuffer sDebugMessage("FmSearchEngine::MoveCursor : catched a DatabaseException (");
240 sDebugMessage.append(OUStringToOString(e.SQLState, RTL_TEXTENCODING_ASCII_US));
241 sDebugMessage.append(") !");
242 OSL_FAIL(sDebugMessage.getStr());
243 #else
244 (void)e;
245 #endif
246 bSuccess = false;
248 catch(Exception const& e)
250 #if OSL_DEBUG_LEVEL > 0
251 OStringBuffer sDebugMessage("FmSearchEngine::MoveCursor : catched an Exception (");
252 sDebugMessage.append(OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US));
253 sDebugMessage.append(") !");
254 OSL_FAIL(sDebugMessage.getStr());
255 #else
256 (void)e;
257 #endif
258 bSuccess = false;
260 catch(...)
262 OSL_FAIL("FmSearchEngine::MoveCursor : catched an unknown Exception !");
263 bSuccess = false;
266 return bSuccess;
270 bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollection::iterator& iter, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
272 bool bSuccess(true);
273 if (m_bForward)
275 ++iter;
276 ++nPos;
277 if (iter == iterEnd)
279 bSuccess = MoveCursor();
280 iter = iterBegin;
281 nPos = 0;
283 } else
285 if (iter == iterBegin)
287 bSuccess = MoveCursor();
288 iter = iterEnd;
289 nPos = iter-iterBegin;
291 --iter;
292 --nPos;
294 return bSuccess;
298 void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< ::com::sun::star::container::XIndexAccess > & xAllFields, sal_Int32 nField)
300 DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ),
301 "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" );
303 // das Feld selber
304 Reference< XInterface > xCurrentField;
305 xAllFields->getByIndex(nField) >>= xCurrentField;
307 // von dem weiss ich jetzt, dass es den DatabaseRecord-Service unterstuetzt (hoffe ich)
308 // fuer den FormatKey und den Typ brauche ich das PropertySet
309 Reference< ::com::sun::star::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY);
311 // die FieldInfo dazu aufbauen
312 FieldInfo fiCurrent;
313 fiCurrent.xContents = Reference< ::com::sun::star::sdb::XColumn > (xCurrentField, UNO_QUERY);
314 fiCurrent.nFormatKey = ::comphelper::getINT32(xProperties->getPropertyValue(FM_PROP_FORMATKEY));
315 fiCurrent.bDoubleHandling = false;
316 if (m_xFormatSupplier.is())
318 Reference< ::com::sun::star::util::XNumberFormats > xNumberFormats(m_xFormatSupplier->getNumberFormats());
320 sal_Int16 nFormatType = ::comphelper::getNumberFormatType(xNumberFormats, fiCurrent.nFormatKey) & ~((sal_Int16)::com::sun::star::util::NumberFormat::DEFINED);
321 fiCurrent.bDoubleHandling = (nFormatType != ::com::sun::star::util::NumberFormat::TEXT);
324 // und merken
325 m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent);
329 OUString FmSearchEngine::FormatField(const FieldInfo& rField)
331 DBG_ASSERT(!m_bUsingTextComponents, "FmSearchEngine::FormatField : im UsingTextComponents-Mode bitte FormatField(sal_Int32) benutzen !");
333 if (!m_xFormatter.is())
334 return OUString();
335 // sonst werden Datumsflder zum Beispiel zu irgendeinem Default-Wert formatiert
337 OUString sReturn;
340 if (rField.bDoubleHandling)
342 double fValue = rField.xContents->getDouble();
343 if (!rField.xContents->wasNull())
344 sReturn = m_xFormatter->convertNumberToString(rField.nFormatKey, fValue);
346 else
348 OUString sValue = rField.xContents->getString();
349 if (!rField.xContents->wasNull())
350 sReturn = m_xFormatter->formatString(rField.nFormatKey, sValue);
353 catch(...)
358 return sReturn;
362 OUString FmSearchEngine::FormatField(sal_Int32 nWhich)
364 if (m_bUsingTextComponents)
366 DBG_ASSERT((sal_uInt32)nWhich < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !");
367 DBG_ASSERT(m_aControlTexts[nWhich] != NULL, "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !");
368 DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !");
370 if (m_nCurrentFieldIndex != -1)
372 DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
373 // analoge Situation wie unten
374 nWhich = m_nCurrentFieldIndex;
377 DBG_ASSERT((nWhich >= 0) && ((sal_uInt32)nWhich < m_aControlTexts.size()),
378 "FmSearchEngine::FormatField : invalid argument nWhich !");
379 return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText();
381 else
383 if (m_nCurrentFieldIndex != -1)
385 DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
386 // ich bin im single-field-modus, da ist auch die richtige Feld-Nummer erlaubt, obwohl dann der richtige ::com::sun::star::sdbcx::Index
387 // fuer meinen Array-Zugriff natuerlich 0 ist
388 nWhich = 0;
391 DBG_ASSERT((nWhich>=0) && (nWhich < (m_arrUsedFields.end() - m_arrUsedFields.begin())),
392 "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
393 return FormatField(m_arrUsedFields[nWhich]);
398 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchSpecial(bool _bSearchForNull, sal_Int32& nFieldPos,
399 FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
401 // die Startposition merken
402 Any aStartMark;
403 try { aStartMark = m_xSearchCursor.getBookmark(); }
404 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
405 FieldCollection::iterator iterInitialField = iterFieldLoop;
408 bool bFound(false);
409 bool bMovedAround(false);
412 if (m_eMode == SM_ALLOWSCHEDULE)
414 Application::Reschedule();
415 Application::Reschedule();
416 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
417 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
418 // or anything like that. So within each loop we create one user event and handle one user event (and no
419 // paintings and these), so the office seems to be frozen while searching.
420 // FS - 70226 - 02.12.99
423 // der aktuell zu vergleichende Inhalt
424 iterFieldLoop->xContents->getString(); // needed for wasNull
425 bFound = (_bSearchForNull ? 1 : 0) == iterFieldLoop->xContents->wasNull();
426 if (bFound)
427 break;
429 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
430 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
431 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
432 // das selbe bestimmt wieder schief geht, also Abbruch
433 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
434 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
435 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
436 m_iterPreviousLocField = iterFieldLoop;
437 // und wech
438 return SR_ERROR;
441 Any aCurrentBookmark;
442 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
443 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
445 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
447 if (nFieldPos == 0)
448 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
449 PropagateProgress(bMovedAround);
450 // if we moved to the starting position we don't have to propagate an 'overflow' message
451 // FS - 07.12.99 - 68530
453 // abbrechen gefordert ?
454 if (CancelRequested())
455 return SR_CANCELED;
457 } while (!bMovedAround);
459 return bFound ? SR_FOUND : SR_NOTFOUND;
463 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchWildcard(const OUString& strExpression, sal_Int32& nFieldPos,
464 FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
466 // die Startposition merken
467 Any aStartMark;
468 try { aStartMark = m_xSearchCursor.getBookmark(); }
469 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
470 FieldCollection::iterator iterInitialField = iterFieldLoop;
472 WildCard aSearchExpression(strExpression);
475 bool bFound(false);
476 bool bMovedAround(false);
479 if (m_eMode == SM_ALLOWSCHEDULE)
481 Application::Reschedule();
482 Application::Reschedule();
483 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
484 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
485 // or anything like that. So within each loop we create one user event and hanel one user event (and no
486 // paintings and these), so the office seems to be frozen while searching.
487 // FS - 70226 - 02.12.99
490 // der aktuell zu vergleichende Inhalt
491 OUString sCurrentCheck;
492 if (m_bFormatter)
493 sCurrentCheck = FormatField(nFieldPos);
494 else
495 sCurrentCheck = iterFieldLoop->xContents->getString();
497 if (!GetCaseSensitive())
498 // norm the string
499 sCurrentCheck = m_aCharacterClassficator.lowercase(sCurrentCheck);
501 // jetzt ist der Test einfach ...
502 bFound = aSearchExpression.Matches(sCurrentCheck);
504 if (bFound)
505 break;
507 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
508 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
509 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
510 // das selbe bestimmt wieder schief geht, also Abbruch
511 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
512 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
513 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
514 m_iterPreviousLocField = iterFieldLoop;
515 // und wech
516 return SR_ERROR;
519 Any aCurrentBookmark;
520 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
521 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
523 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
525 if (nFieldPos == 0)
526 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
527 PropagateProgress(bMovedAround);
528 // if we moved to the starting position we don't have to propagate an 'overflow' message
529 // FS - 07.12.99 - 68530
531 // abbrechen gefordert ?
532 if (CancelRequested())
533 return SR_CANCELED;
535 } while (!bMovedAround);
537 return bFound ? SR_FOUND : SR_NOTFOUND;
541 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchRegularApprox(const OUString& strExpression, sal_Int32& nFieldPos,
542 FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
544 DBG_ASSERT(m_bLevenshtein || m_bRegular,
545 "FmSearchEngine::SearchRegularApprox : ungueltiger Suchmodus !");
546 DBG_ASSERT(!m_bLevenshtein || !m_bRegular,
547 "FmSearchEngine::SearchRegularApprox : kann nicht nach regulaeren Ausdruecken und nach Aehnlichkeiten gleichzeitig suchen !");
549 // Startposition merken
550 Any aStartMark;
551 try { aStartMark = m_xSearchCursor.getBookmark(); }
552 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
553 FieldCollection::iterator iterInitialField = iterFieldLoop;
555 // Parameter sammeln
556 SearchOptions aParam;
557 aParam.algorithmType = m_bRegular ? SearchAlgorithms_REGEXP : SearchAlgorithms_APPROXIMATE;
558 aParam.searchFlag = 0;
559 aParam.transliterateFlags = GetTransliterationFlags();
560 if ( !GetTransliteration() )
561 { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH
562 aParam.transliterateFlags &= TransliterationModules_IGNORE_CASE | TransliterationModules_IGNORE_WIDTH;
564 if (m_bLevenshtein)
566 if (m_bLevRelaxed)
567 aParam.searchFlag |= SearchFlags::LEV_RELAXED;
568 aParam.changedChars = m_nLevOther;
569 aParam.deletedChars = m_nLevShorter;
570 aParam.insertedChars = m_nLevLonger;
572 aParam.searchString = strExpression;
573 aParam.Locale = SvtSysLocale().GetLanguageTag().getLocale();
574 ::utl::TextSearch aLocalEngine(aParam);
577 bool bFound = false;
578 bool bMovedAround(false);
581 if (m_eMode == SM_ALLOWSCHEDULE)
583 Application::Reschedule();
584 Application::Reschedule();
585 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
586 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
587 // or anything like that. So within each loop we create one user event and handle one user event (and no
588 // paintings and these), so the office seems to be frozen while searching.
589 // FS - 70226 - 02.12.99
592 // der aktuell zu vergleichende Inhalt
593 OUString sCurrentCheck;
594 if (m_bFormatter)
595 sCurrentCheck = FormatField(nFieldPos);
596 else
597 sCurrentCheck = iterFieldLoop->xContents->getString();
599 // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it)
601 sal_Int32 nStart = 0, nEnd = sCurrentCheck.getLength();
602 bFound = aLocalEngine.SearchForward(sCurrentCheck, &nStart, &nEnd);
603 // das heisst hier 'forward' aber das bezieht sich nur auf die Suche innerhalb von sCurrentCheck, hat also mit
604 // der Richtung meines Datensatz-Durchwanderns nix zu tun (darum kuemmert sich MoveField)
606 // checken, ob die Position stimmt
607 if (bFound)
609 switch (m_nPosition)
611 case MATCHING_WHOLETEXT :
612 if (nEnd != sCurrentCheck.getLength())
614 bFound = false;
615 break;
617 // laeuft in den naechsten Case rein !
618 case MATCHING_BEGINNING :
619 if (nStart != 0)
620 bFound = false;
621 break;
622 case MATCHING_END :
623 if (nEnd != sCurrentCheck.getLength())
624 bFound = false;
625 break;
629 if (bFound) // immer noch ?
630 break;
632 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
633 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
634 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
635 // das selbe bestimmt wieder schief geht, also Abbruch (ohne Fehlermeldung, von der erwarte ich, dass sie im Move
636 // angezeigt wurde)
637 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
638 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
639 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
640 m_iterPreviousLocField = iterFieldLoop;
641 // und wech
642 return SR_ERROR;
645 Any aCurrentBookmark;
646 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
647 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
648 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
650 if (nFieldPos == 0)
651 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
652 PropagateProgress(bMovedAround);
653 // if we moved to the starting position we don't have to propagate an 'overflow' message
654 // FS - 07.12.99 - 68530
656 // abbrechen gefordert ?
657 if (CancelRequested())
658 return SR_CANCELED;
660 } while (!bMovedAround);
662 return bFound ? SR_FOUND : SR_NOTFOUND;
667 FmSearchEngine::FmSearchEngine(const Reference< XComponentContext >& _rxContext,
668 const Reference< XResultSet > & xCursor, const OUString& sVisibleFields,
669 const Reference< XNumberFormatsSupplier > & xFormatSupplier, FMSEARCH_MODE eMode)
671 :m_xSearchCursor(xCursor)
672 ,m_xFormatSupplier(xFormatSupplier)
673 ,m_aCharacterClassficator( _rxContext, SvtSysLocale().GetLanguageTag() )
674 ,m_aStringCompare( _rxContext )
675 ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
676 ,m_bUsingTextComponents(false)
677 ,m_eSearchForType(SEARCHFOR_STRING)
678 ,m_srResult(SR_FOUND)
679 ,m_bSearchingCurrently(false)
680 ,m_bCancelAsynchRequest(false)
681 ,m_eMode(eMode)
682 ,m_bFormatter(false)
683 ,m_bForward(false)
684 ,m_bWildcard(false)
685 ,m_bRegular(false)
686 ,m_bLevenshtein(false)
687 ,m_bTransliteration(false)
688 ,m_bLevRelaxed(false)
689 ,m_nLevOther(0)
690 ,m_nLevShorter(0)
691 ,m_nLevLonger(0)
692 ,m_nPosition(MATCHING_ANYWHERE)
693 ,m_nTransliterationFlags(0)
696 m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(
697 ::com::sun::star::util::NumberFormatter::create( ::comphelper::getProcessComponentContext() ),
698 UNO_QUERY_THROW);
699 m_xFormatter->attachNumberFormatsSupplier(m_xFormatSupplier);
701 Init(sVisibleFields);
705 FmSearchEngine::FmSearchEngine(const Reference< XComponentContext >& _rxContext,
706 const Reference< XResultSet > & xCursor, const OUString& sVisibleFields,
707 const InterfaceArray& arrFields, FMSEARCH_MODE eMode)
708 :m_xSearchCursor(xCursor)
709 ,m_aCharacterClassficator( _rxContext, SvtSysLocale().GetLanguageTag() )
710 ,m_aStringCompare( _rxContext )
711 ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
712 ,m_bUsingTextComponents(true)
713 ,m_xOriginalIterator(xCursor)
714 ,m_xClonedIterator(m_xOriginalIterator, true)
715 ,m_eSearchForType(SEARCHFOR_STRING)
716 ,m_srResult(SR_FOUND)
717 ,m_bSearchingCurrently(false)
718 ,m_bCancelAsynchRequest(false)
719 ,m_eMode(eMode)
720 ,m_bFormatter(true) // das muss konsistent sein mit m_xSearchCursor, der i.A. == m_xOriginalIterator ist
721 ,m_bForward(false)
722 ,m_bWildcard(false)
723 ,m_bRegular(false)
724 ,m_bLevenshtein(false)
725 ,m_bTransliteration(false)
726 ,m_bLevRelaxed(false)
727 ,m_nLevOther(0)
728 ,m_nLevShorter(0)
729 ,m_nLevLonger(0)
730 ,m_nPosition(MATCHING_ANYWHERE)
731 ,m_nTransliterationFlags(0)
734 fillControlTexts(arrFields);
735 Init(sVisibleFields);
739 FmSearchEngine::~FmSearchEngine()
741 clearControlTexts();
746 void FmSearchEngine::SetIgnoreWidthCJK(bool bSet)
748 if (bSet)
749 m_nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH;
750 else
751 m_nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH;
755 bool FmSearchEngine::GetIgnoreWidthCJK() const
757 return 0 != (m_nTransliterationFlags & TransliterationModules_IGNORE_WIDTH);
761 void FmSearchEngine::SetCaseSensitive(bool bSet)
763 if (bSet)
764 m_nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE;
765 else
766 m_nTransliterationFlags |= TransliterationModules_IGNORE_CASE;
770 bool FmSearchEngine::GetCaseSensitive() const
772 return 0 == (m_nTransliterationFlags & TransliterationModules_IGNORE_CASE);
776 void FmSearchEngine::clearControlTexts()
778 for ( ControlTextSuppliers::iterator aIter = m_aControlTexts.begin();
779 aIter < m_aControlTexts.end();
780 ++aIter
783 delete *aIter;
785 m_aControlTexts.clear();
789 void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields)
791 clearControlTexts();
792 Reference< XInterface > xCurrent;
793 for (sal_uInt32 i=0; i<arrFields.size(); ++i)
795 xCurrent = arrFields.at(i);
796 DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !");
797 // check which type of control this is
798 Reference< ::com::sun::star::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY);
799 if (xAsText.is())
801 m_aControlTexts.insert(m_aControlTexts.end(), new SimpleTextWrapper(xAsText));
802 continue;
805 Reference< ::com::sun::star::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY);
806 if (xAsListBox.is())
808 m_aControlTexts.insert(m_aControlTexts.end(), new ListBoxWrapper(xAsListBox));
809 continue;
812 Reference< ::com::sun::star::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY);
813 DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !");
814 // we don't have any more options ...
815 m_aControlTexts.insert(m_aControlTexts.end(), new CheckBoxWrapper(xAsCheckBox));
820 void FmSearchEngine::Init(const OUString& sVisibleFields)
822 // analyze the fields
823 // additionally, create the mapping: because the list of used columns can be shorter than the list
824 // of columns of the cursor, we need a mapping: "used column numer n" -> "cursor column m"
825 m_arrFieldMapping.clear();
827 // important: The case of the columns does not need to be exact - for instance:
828 // - a user created a form which works on a table, for which the driver returns a column name "COLUMN"
829 // - the driver itself works case-insensitve with column names
830 // - a control in the form is bound to "column" - not the different case
831 // In such a scenario, the form and the field would work okay, but we here need to case for the different case
832 // explicitly
833 // #i8755#
835 // so first of all, check if the database handles identifiers case sensitive
836 Reference< XConnection > xConn;
837 Reference< XDatabaseMetaData > xMeta;
838 Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY );
839 if ( xCursorProps.is() )
843 xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn;
845 catch( const Exception& ) { /* silent this - will be asserted below */ }
847 if ( xConn.is() )
848 xMeta = xConn->getMetaData();
849 OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" );
851 bool bCaseSensitiveIdentifiers = true; // assume case sensivity
852 if ( xMeta.is() )
853 bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers();
855 // now that we have this information, we need a collator which is able to case (in)sentively compare strings
856 m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLanguageTag().getLocale(),
857 bCaseSensitiveIdentifiers ? 0 : ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
861 // der Cursor kann mir einen Record (als PropertySet) liefern, dieser unterstuetzt den DatabaseRecord-Service
862 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
863 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !");
864 Reference< ::com::sun::star::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns();
865 Sequence< OUString > seqFieldNames = xAllFieldNames->getElementNames();
866 OUString* pFieldNames = seqFieldNames.getArray();
869 OUString sCurrentField;
870 OUString sVis(sVisibleFields.getStr());
871 sal_Int32 nIndex = 0;
874 sCurrentField = sVis.getToken(0, ';' , nIndex);
876 // in der Feld-Sammlung suchen
877 sal_Int32 nFoundIndex = -1;
878 for (sal_Int32 j=0; j<seqFieldNames.getLength(); ++j, ++pFieldNames)
880 if ( 0 == m_aStringCompare.compareString( *pFieldNames, sCurrentField ) )
882 nFoundIndex = j;
883 break;
886 // set the field selection back to the first
887 pFieldNames = seqFieldNames.getArray();
888 DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Invalid field name were given !");
889 m_arrFieldMapping.push_back(nFoundIndex);
891 while ( nIndex >= 0 );
893 catch (const Exception&)
895 OSL_FAIL("Exception occurred!");
901 void FmSearchEngine::SetFormatterUsing(bool bSet)
903 if (m_bFormatter == bSet)
904 return;
905 m_bFormatter = bSet;
907 if (m_bUsingTextComponents)
909 // ich benutzte keinen Formatter, sondern TextComponents -> der SearchIterator muss angepasst werden
912 if (m_bFormatter)
914 DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
915 m_xSearchCursor = m_xOriginalIterator;
916 m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark());
917 // damit ich mit dem neuen Iterator wirklich dort weitermache, wo ich vorher aufgehoert habe
919 else
921 DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
922 m_xSearchCursor = m_xClonedIterator;
923 m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark());
926 catch( const Exception& )
928 DBG_UNHANDLED_EXCEPTION();
931 // ich muss die Fields neu binden, da der Textaustausch eventuell ueber diese Fields erfolgt und sich der unterliegende Cursor
932 // geaendert hat
933 RebuildUsedFields(m_nCurrentFieldIndex, true);
935 else
936 InvalidatePreviousLoc();
940 void FmSearchEngine::PropagateProgress(bool _bDontPropagateOverflow)
942 if (m_aProgressHandler.IsSet())
944 FmSearchProgress aProgress;
947 aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS;
948 aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
949 if (m_bForward)
950 aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst();
951 else
952 aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast();
954 catch( const Exception& )
956 DBG_UNHANDLED_EXCEPTION();
959 m_aProgressHandler.Call(&aProgress);
964 void FmSearchEngine::SearchNextImpl()
966 DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard),
967 "FmSearchEngine::SearchNextImpl : Suchparameter schliessen sich gegenseitig aus !");
969 DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : habe ungueltigen Iterator !");
971 // die Parameter der Suche
972 OUString strSearchExpression(m_strSearchExpression); // brauche ich non-const
973 if (!GetCaseSensitive())
974 // norm the string
975 strSearchExpression = m_aCharacterClassficator.lowercase(strSearchExpression);
977 if (!m_bRegular && !m_bLevenshtein)
978 { // 'normale' Suche fuehre ich auf jeden Fall ueber WildCards durch, muss aber vorher je nach Modus den OUString anpassen
980 if (!m_bWildcard)
981 { // da natuerlich in allen anderen Faellen auch * und ? im Suchstring erlaubt sind, aber nicht als WildCards zaehlen
982 // sollen, muss ich normieren
983 OUString aTmp(strSearchExpression);
984 const OUString s_sStar("\\*");
985 const OUString s_sQuotation("\\?");
986 aTmp = aTmp.replaceAll("*", s_sStar);
987 aTmp = aTmp.replaceAll("?", s_sQuotation);
988 strSearchExpression = aTmp;
990 switch (m_nPosition)
992 case MATCHING_ANYWHERE :
993 strSearchExpression = "*" + strSearchExpression + "*";
994 break;
995 case MATCHING_BEGINNING :
996 strSearchExpression = strSearchExpression + "*";
997 break;
998 case MATCHING_END :
999 strSearchExpression = "*" + strSearchExpression;
1000 break;
1001 case MATCHING_WHOLETEXT :
1002 break;
1003 default :
1004 OSL_FAIL("FmSearchEngine::SearchNextImpl() : die Methoden-Listbox duerfte nur 4 Eintraege enthalten ...");
1009 // fuer Arbeit auf Feldliste
1010 FieldCollection::iterator iterBegin = m_arrUsedFields.begin();
1011 FieldCollection::iterator iterEnd = m_arrUsedFields.end();
1012 FieldCollection::iterator iterFieldCheck;
1014 sal_Int32 nFieldPos;
1016 if (HasPreviousLoc())
1018 DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()),
1019 "FmSearchEngine::SearchNextImpl : ungueltige Position !");
1020 iterFieldCheck = m_iterPreviousLocField;
1021 // im Feld nach (oder vor) der letzten Fundstelle weitermachen
1022 nFieldPos = iterFieldCheck - iterBegin;
1023 MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1025 else
1027 if (m_bForward)
1028 iterFieldCheck = iterBegin;
1029 else
1031 iterFieldCheck = iterEnd;
1032 --iterFieldCheck;
1034 nFieldPos = iterFieldCheck - iterBegin;
1037 PropagateProgress(true);
1038 SEARCH_RESULT srResult;
1039 if (m_eSearchForType != SEARCHFOR_STRING)
1040 srResult = SearchSpecial(m_eSearchForType == SEARCHFOR_NULL, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1041 else if (!m_bRegular && !m_bLevenshtein)
1042 srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1043 else
1044 srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1046 m_srResult = srResult;
1048 if (SR_ERROR == m_srResult)
1049 return;
1051 // gefunden ?
1052 if (SR_FOUND == m_srResult)
1054 // die Pos merken
1055 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
1056 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
1057 m_iterPreviousLocField = iterFieldCheck;
1059 else
1060 // die "letzte Fundstelle" invalidieren
1061 InvalidatePreviousLoc();
1065 IMPL_LINK(FmSearchEngine, OnSearchTerminated, FmSearchThread*, /*pThread*/)
1067 if (!m_aProgressHandler.IsSet())
1068 return 0L;
1070 FmSearchProgress aProgress;
1073 switch (m_srResult)
1075 case SR_ERROR :
1076 aProgress.aSearchState = FmSearchProgress::STATE_ERROR;
1077 break;
1078 case SR_FOUND :
1079 aProgress.aSearchState = FmSearchProgress::STATE_SUCCESSFULL;
1080 aProgress.aBookmark = m_aPreviousLocBookmark;
1081 aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin();
1082 break;
1083 case SR_NOTFOUND :
1084 aProgress.aSearchState = FmSearchProgress::STATE_NOTHINGFOUND;
1085 aProgress.aBookmark = m_xSearchCursor.getBookmark();
1086 break;
1087 case SR_CANCELED :
1088 aProgress.aSearchState = FmSearchProgress::STATE_CANCELED;
1089 aProgress.aBookmark = m_xSearchCursor.getBookmark();
1090 break;
1092 aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
1094 catch( const Exception& )
1096 DBG_UNHANDLED_EXCEPTION();
1099 // per definitionem muss der Link Thread-sicher sein (das verlange ich einfach), so dass ich mich um so etwas hier nicht kuemmern muss
1100 m_aProgressHandler.Call(&aProgress);
1102 m_bSearchingCurrently = false;
1103 return 0L;
1107 IMPL_LINK(FmSearchEngine, OnNewRecordCount, void*, pCounterAsVoid)
1109 if (!m_aProgressHandler.IsSet())
1110 return 0L;
1112 FmSearchProgress aProgress;
1113 aProgress.nCurrentRecord = (sal_uIntPtr)pCounterAsVoid;
1114 aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS_COUNTING;
1115 m_aProgressHandler.Call(&aProgress);
1117 return 0L;
1121 bool FmSearchEngine::CancelRequested()
1123 m_aCancelAsynchAccess.acquire();
1124 bool bReturn = m_bCancelAsynchRequest;
1125 m_aCancelAsynchAccess.release();
1126 return bReturn;
1130 void FmSearchEngine::CancelSearch()
1132 m_aCancelAsynchAccess.acquire();
1133 m_bCancelAsynchRequest = true;
1134 m_aCancelAsynchAccess.release();
1138 bool FmSearchEngine::SwitchToContext(const Reference< ::com::sun::star::sdbc::XResultSet > & xCursor, const OUString& sVisibleFields, const InterfaceArray& arrFields,
1139 sal_Int32 nFieldIndex)
1141 DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !");
1142 if (m_bSearchingCurrently)
1143 return false;
1145 m_xSearchCursor = xCursor;
1146 m_xOriginalIterator = xCursor;
1147 m_xClonedIterator = CursorWrapper(m_xOriginalIterator, true);
1148 m_bUsingTextComponents = true;
1150 fillControlTexts(arrFields);
1152 Init(sVisibleFields);
1153 RebuildUsedFields(nFieldIndex, true);
1155 return true;
1159 void FmSearchEngine::ImplStartNextSearch()
1161 m_bCancelAsynchRequest = false;
1162 m_bSearchingCurrently = true;
1164 if (m_eMode == SM_USETHREAD)
1166 FmSearchThread* pSearcher = new FmSearchThread(this);
1167 // der loescht sich nach Beendigung selber ...
1168 pSearcher->setTerminationHandler(LINK(this, FmSearchEngine, OnSearchTerminated));
1170 pSearcher->createSuspended();
1171 pSearcher->setPriority(osl_Thread_PriorityLowest);
1172 pSearcher->resume();
1174 else
1176 SearchNextImpl();
1177 LINK(this, FmSearchEngine, OnSearchTerminated).Call(NULL);
1182 void FmSearchEngine::SearchNext(const OUString& strExpression)
1184 m_strSearchExpression = strExpression;
1185 m_eSearchForType = SEARCHFOR_STRING;
1186 ImplStartNextSearch();
1190 void FmSearchEngine::SearchNextSpecial(bool _bSearchForNull)
1192 m_eSearchForType = _bSearchForNull ? SEARCHFOR_NULL : SEARCHFOR_NOTNULL;
1193 ImplStartNextSearch();
1197 void FmSearchEngine::StartOver(const OUString& strExpression)
1201 if (m_bForward)
1202 m_xSearchCursor.first();
1203 else
1204 m_xSearchCursor.last();
1206 catch( const Exception& )
1208 DBG_UNHANDLED_EXCEPTION();
1209 return;
1212 InvalidatePreviousLoc();
1213 SearchNext(strExpression);
1217 void FmSearchEngine::StartOverSpecial(bool _bSearchForNull)
1221 if (m_bForward)
1222 m_xSearchCursor.first();
1223 else
1224 m_xSearchCursor.last();
1226 catch( const Exception& )
1228 DBG_UNHANDLED_EXCEPTION();
1229 return;
1232 InvalidatePreviousLoc();
1233 SearchNextSpecial(_bSearchForNull);
1237 void FmSearchEngine::InvalidatePreviousLoc()
1239 m_aPreviousLocBookmark.setValue(0,getVoidCppuType());
1240 m_iterPreviousLocField = m_arrUsedFields.end();
1244 void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, bool bForce)
1246 if (!bForce && (nFieldIndex == m_nCurrentFieldIndex))
1247 return;
1248 // (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)
1250 DBG_ASSERT((nFieldIndex == -1) ||
1251 ((nFieldIndex >= 0) &&
1252 (static_cast<size_t>(nFieldIndex) < m_arrFieldMapping.size())),
1253 "FmSearchEngine::RebuildUsedFields : nFieldIndex is invalid!");
1254 // alle Felder, die ich durchsuchen muss, einsammeln
1255 m_arrUsedFields.clear();
1256 if (nFieldIndex == -1)
1258 Reference< ::com::sun::star::container::XIndexAccess > xFields;
1259 for (size_t i=0; i<m_arrFieldMapping.size(); ++i)
1261 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1262 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1263 xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
1264 BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[i]);
1267 else
1269 Reference< ::com::sun::star::container::XIndexAccess > xFields;
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[static_cast< size_t >(nFieldIndex)]);
1276 m_nCurrentFieldIndex = nFieldIndex;
1277 // und natuerlich beginne ich die naechste Suche wieder jungfraeulich
1278 InvalidatePreviousLoc();
1281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */