update dev300-m58
[ooovba.git] / svx / source / form / fmsrcimp.cxx
blob66acca4748070206cb5c0cf09ca327b92eb4ae95
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fmsrcimp.cxx,v $
10 * $Revision: 1.37 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #ifndef _SVX_FMRESIDS_HRC
35 #include "fmresids.hrc"
36 #endif
37 #include "fmtools.hxx"
38 #include "fmsrccfg.hxx"
39 #include <tools/debug.hxx>
40 #include <tools/diagnose_ex.h>
41 #include <tools/wldcrd.hxx>
42 #include <vcl/msgbox.hxx>
43 #include <tools/shl.hxx>
44 #include <svx/dialmgr.hxx>
45 #include <cppuhelper/servicefactory.hxx>
46 #include <vcl/svapp.hxx>
47 #include <unotools/textsearch.hxx>
48 #include <com/sun/star/util/SearchOptions.hpp>
49 #include <com/sun/star/util/SearchAlgorithms.hpp>
50 #include <com/sun/star/util/SearchResult.hpp>
51 #include <com/sun/star/util/SearchFlags.hpp>
52 #include <com/sun/star/lang/Locale.hpp>
53 #include <com/sun/star/i18n/TransliterationModules.hpp>
54 #include <com/sun/star/i18n/CollatorOptions.hpp>
56 #ifndef _COM_SUN_STAR_SDDB_XCOLUMNSSUPPLIER_HPP_
57 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
58 #endif
59 #include <com/sun/star/util/XNumberFormatter.hpp>
60 #include <com/sun/star/util/NumberFormat.hpp>
61 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
62 #include <com/sun/star/util/XNumberFormats.hpp>
63 #include <comphelper/processfactory.hxx>
65 #ifndef _SVX_FMPROP_HRC
66 #include "fmprop.hrc"
67 #endif
68 #include "fmservs.hxx"
69 #include "fmsrcimp.hxx"
70 #include <svx/fmsearch.hxx>
72 #ifndef _FMSEARCH_HRC
73 #include "fmsearch.hrc"
74 #endif
75 #include <comphelper/numbers.hxx>
76 #include <svtools/syslocale.hxx>
78 #define EQUAL_BOOKMARKS(a, b) a == b
80 #define IFACECAST(c) ((const Reference< XInterface >&)c)
81 // SUN C52 has some ambiguities without this cast ....
83 using namespace ::com::sun::star::uno;
84 using namespace ::com::sun::star::util;
85 using namespace ::com::sun::star::lang;
86 using namespace ::com::sun::star::sdbc;
87 using namespace ::com::sun::star::i18n;
88 using namespace ::com::sun::star::beans;
89 using namespace ::svxform;
91 // ***************************************************************************************************
93 // ***************************************************************************************************
95 SV_IMPL_OBJARR(SvInt32Array, sal_Int32);
97 //========================================================================
98 // = FmSearchThread
99 //------------------------------------------------------------------------
100 void FmSearchThread::run()
102 m_pEngine->SearchNextImpl();
105 //------------------------------------------------------------------------
106 void FmSearchThread::onTerminated()
108 if (m_aTerminationHdl.IsSet())
109 m_aTerminationHdl.Call(this);
110 delete this;
113 //========================================================================
114 // = FmRecordCountListener
116 // SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject);
118 DBG_NAME(FmRecordCountListener);
119 //------------------------------------------------------------------------
120 FmRecordCountListener::FmRecordCountListener(const Reference< ::com::sun::star::sdbc::XResultSet > & dbcCursor)
122 DBG_CTOR(FmRecordCountListener,NULL);
124 m_xListening = Reference< ::com::sun::star::beans::XPropertySet > (dbcCursor, UNO_QUERY);
125 if (!m_xListening.is())
126 return;
128 if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL)))
130 m_xListening = NULL;
131 // there's nothing to do as the record count is already known
132 return;
135 m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
138 //------------------------------------------------------------------------
139 Link FmRecordCountListener::SetPropChangeHandler(const Link& lnk)
141 Link lnkReturn = m_lnkWhoWantsToKnow;
142 m_lnkWhoWantsToKnow = lnk;
144 if (m_xListening.is())
145 NotifyCurrentCount();
147 return lnkReturn;
150 //------------------------------------------------------------------------
151 FmRecordCountListener::~FmRecordCountListener()
154 DBG_DTOR(FmRecordCountListener,NULL);
157 //------------------------------------------------------------------------
158 void FmRecordCountListener::DisConnect()
160 if(m_xListening.is())
161 m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this);
162 m_xListening = NULL;
165 //------------------------------------------------------------------------
166 void SAL_CALL FmRecordCountListener::disposing(const ::com::sun::star::lang::EventObject& /*Source*/) throw( RuntimeException )
168 DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !");
169 DisConnect();
172 //------------------------------------------------------------------------
173 void FmRecordCountListener::NotifyCurrentCount()
175 if (m_lnkWhoWantsToKnow.IsSet())
177 DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?");
178 void* pTheCount = (void*)::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT));
179 m_lnkWhoWantsToKnow.Call(pTheCount);
183 //------------------------------------------------------------------------
184 void FmRecordCountListener::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& /*evt*/) throw(::com::sun::star::uno::RuntimeException)
186 NotifyCurrentCount();
189 //========================================================================
190 // FmSearchEngine - local classes
191 //------------------------------------------------------------------------
192 SimpleTextWrapper::SimpleTextWrapper(const Reference< ::com::sun::star::awt::XTextComponent > & _xText)
193 :ControlTextWrapper(_xText.get())
194 ,m_xText(_xText)
196 DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !");
199 //------------------------------------------------------------------------
200 ::rtl::OUString SimpleTextWrapper::getCurrentText() const
202 return m_xText->getText();
205 //------------------------------------------------------------------------
206 ListBoxWrapper::ListBoxWrapper(const Reference< ::com::sun::star::awt::XListBox > & _xBox)
207 :ControlTextWrapper(_xBox.get())
208 ,m_xBox(_xBox)
210 DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !");
213 //------------------------------------------------------------------------
214 ::rtl::OUString ListBoxWrapper::getCurrentText() const
216 return m_xBox->getSelectedItem();
219 //------------------------------------------------------------------------
220 CheckBoxWrapper::CheckBoxWrapper(const Reference< ::com::sun::star::awt::XCheckBox > & _xBox)
221 :ControlTextWrapper(_xBox.get())
222 ,m_xBox(_xBox)
224 DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !");
227 //------------------------------------------------------------------------
228 ::rtl::OUString CheckBoxWrapper::getCurrentText() const
230 switch ((TriState)m_xBox->getState())
232 case STATE_NOCHECK: return rtl::OUString::createFromAscii("0");
233 case STATE_CHECK: return rtl::OUString::createFromAscii("1");
234 default: break;
236 return rtl::OUString();
239 //========================================================================
240 // = FmSearchEngine
241 //------------------------------------------------------------------------
242 sal_Bool FmSearchEngine::MoveCursor()
244 sal_Bool bSuccess = sal_True;
247 if (m_bForward)
248 if (m_xSearchCursor.isLast())
249 m_xSearchCursor.first();
250 else
251 m_xSearchCursor.next();
252 else
253 if (m_xSearchCursor.isFirst())
255 FmRecordCountListener* prclListener = new FmRecordCountListener(m_xSearchCursor);
256 prclListener->acquire();
257 prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount));
259 m_xSearchCursor.last();
261 prclListener->DisConnect();
262 prclListener->release();
264 else
265 m_xSearchCursor.previous();
267 catch(::com::sun::star::sdbc::SQLException e)
269 #if OSL_DEBUG_LEVEL > 0
270 String sDebugMessage;
271 sDebugMessage.AssignAscii("FmSearchEngine::MoveCursor : catched a DatabaseException (");
272 sDebugMessage += (const sal_Unicode*)e.SQLState;
273 sDebugMessage.AppendAscii(") !");
274 DBG_ERROR(ByteString(sDebugMessage, RTL_TEXTENCODING_ASCII_US).GetBuffer());
275 #endif
276 bSuccess = sal_False;
278 catch(Exception e)
280 #if OSL_DEBUG_LEVEL > 0
281 UniString sDebugMessage;
282 sDebugMessage.AssignAscii("FmSearchEngine::MoveCursor : catched an Exception (");
283 sDebugMessage += (const sal_Unicode*)e.Message;
284 sDebugMessage.AppendAscii(") !");
285 DBG_ERROR(ByteString(sDebugMessage, RTL_TEXTENCODING_ASCII_US).GetBuffer());
286 #endif
287 bSuccess = sal_False;
289 catch(...)
291 DBG_ERROR("FmSearchEngine::MoveCursor : catched an unknown Exception !");
292 bSuccess = sal_False;
295 return bSuccess;
298 //------------------------------------------------------------------------
299 sal_Bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollectionIterator& iter, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
301 sal_Bool bSuccess(sal_True);
302 if (m_bForward)
304 ++iter;
305 ++nPos;
306 if (iter == iterEnd)
308 bSuccess = MoveCursor();
309 iter = iterBegin;
310 nPos = 0;
312 } else
314 if (iter == iterBegin)
316 bSuccess = MoveCursor();
317 iter = iterEnd;
318 nPos = iter-iterBegin;
320 --iter;
321 --nPos;
323 return bSuccess;
326 //------------------------------------------------------------------------
327 void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< ::com::sun::star::container::XIndexAccess > & xAllFields, sal_Int32 nField)
329 DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ),
330 "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" );
332 // das Feld selber
333 Reference< XInterface > xCurrentField;
334 xAllFields->getByIndex(nField) >>= xCurrentField;
336 // von dem weiss ich jetzt, dass es den DatabaseRecord-Service unterstuetzt (hoffe ich)
337 // fuer den FormatKey und den Typ brauche ich das PropertySet
338 Reference< ::com::sun::star::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY);
340 // die FieldInfo dazu aufbauen
341 FieldInfo fiCurrent;
342 fiCurrent.xContents = Reference< ::com::sun::star::sdb::XColumn > (xCurrentField, UNO_QUERY);
343 fiCurrent.nFormatKey = ::comphelper::getINT32(xProperties->getPropertyValue(FM_PROP_FORMATKEY));
344 fiCurrent.bDoubleHandling = sal_False;
345 if (m_xFormatSupplier.is())
347 Reference< ::com::sun::star::util::XNumberFormats > xNumberFormats(m_xFormatSupplier->getNumberFormats());
349 sal_Int16 nFormatType = ::comphelper::getNumberFormatType(xNumberFormats, fiCurrent.nFormatKey) & ~((sal_Int16)::com::sun::star::util::NumberFormat::DEFINED);
350 fiCurrent.bDoubleHandling = (nFormatType != ::com::sun::star::util::NumberFormat::TEXT);
353 // und merken
354 m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent);
357 //------------------------------------------------------------------------
358 ::rtl::OUString FmSearchEngine::FormatField(const FieldInfo& rField)
360 DBG_ASSERT(!m_bUsingTextComponents, "FmSearchEngine::FormatField : im UsingTextComponents-Mode bitte FormatField(sal_Int32) benutzen !");
362 if (!m_xFormatter.is())
363 return ::rtl::OUString();
364 // sonst werden Datumsflder zum Beispiel zu irgendeinem Default-Wert formatiert
366 ::rtl::OUString sReturn;
369 if (rField.bDoubleHandling)
371 double fValue = rField.xContents->getDouble();
372 if (!rField.xContents->wasNull())
373 sReturn = m_xFormatter->convertNumberToString(rField.nFormatKey, fValue);
375 else
377 ::rtl::OUString sValue = rField.xContents->getString();
378 if (!rField.xContents->wasNull())
379 sReturn = m_xFormatter->formatString(rField.nFormatKey, sValue);
382 catch(...)
387 return sReturn;
390 //------------------------------------------------------------------------
391 ::rtl::OUString FmSearchEngine::FormatField(sal_Int32 nWhich)
393 if (m_bUsingTextComponents)
395 DBG_ASSERT((sal_uInt32)nWhich < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !");
396 DBG_ASSERT(m_aControlTexts[nWhich] != NULL, "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !");
397 DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !");
399 if (m_nCurrentFieldIndex != -1)
401 DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
402 // analoge Situation wie unten
403 nWhich = m_nCurrentFieldIndex;
406 DBG_ASSERT((nWhich >= 0) && ((sal_uInt32)nWhich < m_aControlTexts.size()),
407 "FmSearchEngine::FormatField : invalid argument nWhich !");
408 return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText();
410 else
412 if (m_nCurrentFieldIndex != -1)
414 DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
415 // ich bin im single-field-modus, da ist auch die richtige Feld-Nummer erlaubt, obwohl dann der richtige ::com::sun::star::sdbcx::Index
416 // fuer meinen Array-Zugriff natuerlich 0 ist
417 nWhich = 0;
420 DBG_ASSERT((nWhich>=0) && (nWhich < (m_arrUsedFields.end() - m_arrUsedFields.begin())),
421 "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig");
422 return FormatField(m_arrUsedFields[nWhich]);
426 //------------------------------------------------------------------------
427 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchSpecial(sal_Bool _bSearchForNull, sal_Int32& nFieldPos,
428 FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
430 // die Startposition merken
431 Any aStartMark;
432 try { aStartMark = m_xSearchCursor.getBookmark(); }
433 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
434 FieldCollectionIterator iterInitialField = iterFieldLoop;
436 // --------------------------------------------------------------
437 sal_Bool bFound(sal_False);
438 sal_Bool bMovedAround(sal_False);
441 if (m_eMode == SM_ALLOWSCHEDULE) //CHINA001 if (m_eMode == FmSearchDialog::SM_ALLOWSCHEDULE)
443 Application::Reschedule();
444 Application::Reschedule();
445 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
446 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
447 // or anything like that. So within each loop we create one user event and handle one user event (and no
448 // paintings and these), so the office seems to be frozen while searching.
449 // FS - 70226 - 02.12.99
452 // der aktuell zu vergleichende Inhalt
453 iterFieldLoop->xContents->getString(); // needed for wasNull
454 bFound = _bSearchForNull == iterFieldLoop->xContents->wasNull();
455 if (bFound)
456 break;
458 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
459 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
460 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
461 // das selbe bestimmt wieder schief geht, also Abbruch
462 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
463 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
464 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
465 m_iterPreviousLocField = iterFieldLoop;
466 // und wech
467 return SR_ERROR;
470 Any aCurrentBookmark;
471 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
472 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
474 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
476 if (nFieldPos == 0)
477 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
478 PropagateProgress(bMovedAround);
479 // if we moved to the starting position we don't have to propagate an 'overflow' message
480 // FS - 07.12.99 - 68530
482 // abbrechen gefordert ?
483 if (CancelRequested())
484 return SR_CANCELED;
486 } while (!bMovedAround);
488 return bFound ? SR_FOUND : SR_NOTFOUND;
491 //------------------------------------------------------------------------
492 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchWildcard(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos,
493 FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
495 // die Startposition merken
496 Any aStartMark;
497 try { aStartMark = m_xSearchCursor.getBookmark(); }
498 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
499 FieldCollectionIterator iterInitialField = iterFieldLoop;
501 WildCard aSearchExpression(strExpression);
503 // --------------------------------------------------------------
504 sal_Bool bFound(sal_False);
505 sal_Bool bMovedAround(sal_False);
508 if (m_eMode == SM_ALLOWSCHEDULE) //CHINA001 if (m_eMode == FmSearchDialog::SM_ALLOWSCHEDULE)
510 Application::Reschedule();
511 Application::Reschedule();
512 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
513 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
514 // or anything like that. So within each loop we create one user event and hanel one user event (and no
515 // paintings and these), so the office seems to be frozen while searching.
516 // FS - 70226 - 02.12.99
519 // der aktuell zu vergleichende Inhalt
520 ::rtl::OUString sCurrentCheck;
521 if (m_bFormatter)
522 sCurrentCheck = FormatField(nFieldPos);
523 else
524 sCurrentCheck = iterFieldLoop->xContents->getString();
526 if (!GetCaseSensitive())
527 // norm the string
528 m_aCharacterClassficator.toLower_rtl(sCurrentCheck);
530 // jetzt ist der Test einfach ...
531 bFound = aSearchExpression.Matches(sCurrentCheck);
533 if (bFound)
534 break;
536 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
537 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
538 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
539 // das selbe bestimmt wieder schief geht, also Abbruch
540 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
541 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
542 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
543 m_iterPreviousLocField = iterFieldLoop;
544 // und wech
545 return SR_ERROR;
548 Any aCurrentBookmark;
549 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
550 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
552 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
554 if (nFieldPos == 0)
555 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
556 PropagateProgress(bMovedAround);
557 // if we moved to the starting position we don't have to propagate an 'overflow' message
558 // FS - 07.12.99 - 68530
560 // abbrechen gefordert ?
561 if (CancelRequested())
562 return SR_CANCELED;
564 } while (!bMovedAround);
566 return bFound ? SR_FOUND : SR_NOTFOUND;
569 //------------------------------------------------------------------------
570 FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchRegularApprox(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos,
571 FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd)
573 DBG_ASSERT(m_bLevenshtein || m_bRegular,
574 "FmSearchEngine::SearchRegularApprox : ungueltiger Suchmodus !");
575 DBG_ASSERT(!m_bLevenshtein || !m_bRegular,
576 "FmSearchEngine::SearchRegularApprox : kann nicht nach regulaeren Ausdruecken und nach Aehnlichkeiten gleichzeitig suchen !");
578 // Startposition merken
579 Any aStartMark;
580 try { aStartMark = m_xSearchCursor.getBookmark(); }
581 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
582 FieldCollectionIterator iterInitialField = iterFieldLoop;
584 // Parameter sammeln
585 SearchOptions aParam;
586 aParam.algorithmType = m_bRegular ? SearchAlgorithms_REGEXP : SearchAlgorithms_APPROXIMATE;
587 aParam.searchFlag = 0;
588 aParam.transliterateFlags = GetTransliterationFlags();
589 if ( !GetTransliteration() )
590 { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH
591 aParam.transliterateFlags &= TransliterationModules_IGNORE_CASE | TransliterationModules_IGNORE_WIDTH;
593 if (m_bLevenshtein)
595 if (m_bLevRelaxed)
596 aParam.searchFlag |= SearchFlags::LEV_RELAXED;
597 aParam.changedChars = m_nLevOther;
598 aParam.deletedChars = m_nLevShorter;
599 aParam.insertedChars = m_nLevLonger;
601 aParam.searchString = strExpression;
602 aParam.Locale = SvtSysLocale().GetLocaleData().getLocale();
603 ::utl::TextSearch aLocalEngine(aParam);
605 // --------------------------------------------------------------
606 bool bFound = false;
607 sal_Bool bMovedAround(sal_False);
610 if (m_eMode == SM_ALLOWSCHEDULE) //CHINA001 if (m_eMode == FmSearchDialog::SM_ALLOWSCHEDULE)
612 Application::Reschedule();
613 Application::Reschedule();
614 // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
615 // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
616 // or anything like that. So within each loop we create one user event and handle one user event (and no
617 // paintings and these), so the office seems to be frozen while searching.
618 // FS - 70226 - 02.12.99
621 // der aktuell zu vergleichende Inhalt
622 ::rtl::OUString sCurrentCheck;
623 if (m_bFormatter)
624 sCurrentCheck = FormatField(nFieldPos);
625 else
626 sCurrentCheck = iterFieldLoop->xContents->getString();
628 // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it)
630 xub_StrLen nStart = 0, nEnd = (xub_StrLen)sCurrentCheck.getLength();
631 bFound = aLocalEngine.SearchFrwrd(sCurrentCheck, &nStart, &nEnd);
632 // das heisst hier 'forward' aber das bezieht sich nur auf die Suche innerhalb von sCurrentCheck, hat also mit
633 // der Richtung meines Datensatz-Durchwanderns nix zu tun (darum kuemmert sich MoveField)
635 // checken, ob die Position stimmt
636 if (bFound)
638 switch (m_nPosition)
640 case MATCHING_WHOLETEXT :
641 if (nEnd != sCurrentCheck.getLength())
643 bFound = false;
644 break;
646 // laeuft in den naechsten Case rein !
647 case MATCHING_BEGINNING :
648 if (nStart != 0)
649 bFound = false;
650 break;
651 case MATCHING_END :
652 if (nEnd != sCurrentCheck.getLength())
653 bFound = false;
654 break;
658 if (bFound) // immer noch ?
659 break;
661 // naechstes Feld (implizit naechster Datensatz, wenn noetig)
662 if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
663 { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau
664 // das selbe bestimmt wieder schief geht, also Abbruch (ohne Fehlermeldung, von der erwarte ich, dass sie im Move
665 // angezeigt wurde)
666 // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht :
667 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
668 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
669 m_iterPreviousLocField = iterFieldLoop;
670 // und wech
671 return SR_ERROR;
674 Any aCurrentBookmark;
675 try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
676 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; }
677 bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
679 if (nFieldPos == 0)
680 // das heisst, ich habe mich auf einen neuen Datensatz bewegt
681 PropagateProgress(bMovedAround);
682 // if we moved to the starting position we don't have to propagate an 'overflow' message
683 // FS - 07.12.99 - 68530
685 // abbrechen gefordert ?
686 if (CancelRequested())
687 return SR_CANCELED;
689 } while (!bMovedAround);
691 return bFound ? SR_FOUND : SR_NOTFOUND;
695 DBG_NAME(FmSearchEngine);
696 //------------------------------------------------------------------------
697 FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB,
698 const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields,
699 const Reference< XNumberFormatsSupplier > & xFormatSupplier, FMSEARCH_MODE eMode)//CHINA001 const Reference< XNumberFormatsSupplier > & xFormatSupplier, FmSearchDialog::SEARCH_MODE eMode)
700 :m_xSearchCursor(xCursor)
701 ,m_xFormatSupplier(xFormatSupplier)
702 ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() )
703 ,m_aStringCompare( _rxORB )
704 ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
705 ,m_bUsingTextComponents(sal_False)
706 ,m_eSearchForType(SEARCHFOR_STRING)
707 ,m_srResult(SR_FOUND)
708 ,m_bSearchingCurrently(sal_False)
709 ,m_bCancelAsynchRequest(sal_False)
710 ,m_eMode(eMode)
711 ,m_bFormatter(sal_False)
712 ,m_bForward(sal_False)
713 ,m_bWildcard(sal_False)
714 ,m_bRegular(sal_False)
715 ,m_bLevenshtein(sal_False)
716 ,m_bTransliteration(sal_False)
717 ,m_bLevRelaxed(sal_False)
718 ,m_nLevOther(0)
719 ,m_nLevShorter(0)
720 ,m_nLevLonger(0)
721 ,m_nPosition(MATCHING_ANYWHERE)
722 ,m_nTransliterationFlags(0)
724 DBG_CTOR(FmSearchEngine,NULL);
726 m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter > (::comphelper::getProcessServiceFactory()
727 ->createInstance(FM_NUMBER_FORMATTER), UNO_QUERY);
728 if (m_xFormatter.is())
729 m_xFormatter->attachNumberFormatsSupplier(m_xFormatSupplier);
731 Init(sVisibleFields);
734 //------------------------------------------------------------------------
735 FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB,
736 const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields,
737 const InterfaceArray& arrFields, FMSEARCH_MODE eMode)//CHINA001 const InterfaceArray& arrFields, FmSearchDialog::SEARCH_MODE eMode)
738 :m_xSearchCursor(xCursor)
739 ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() )
740 ,m_aStringCompare( _rxORB )
741 ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig'
742 ,m_bUsingTextComponents(sal_True)
743 ,m_xOriginalIterator(xCursor)
744 ,m_xClonedIterator(m_xOriginalIterator, sal_True)
745 ,m_eSearchForType(SEARCHFOR_STRING)
746 ,m_srResult(SR_FOUND)
747 ,m_bSearchingCurrently(sal_False)
748 ,m_bCancelAsynchRequest(sal_False)
749 ,m_eMode(eMode)
750 ,m_bFormatter(sal_True) // das muss konsistent sein mit m_xSearchCursor, der i.A. == m_xOriginalIterator ist
751 ,m_bForward(sal_False)
752 ,m_bWildcard(sal_False)
753 ,m_bRegular(sal_False)
754 ,m_bLevenshtein(sal_False)
755 ,m_bTransliteration(sal_False)
756 ,m_bLevRelaxed(sal_False)
757 ,m_nLevOther(0)
758 ,m_nLevShorter(0)
759 ,m_nLevLonger(0)
760 ,m_nPosition(MATCHING_ANYWHERE)
761 ,m_nTransliterationFlags(0)
763 DBG_CTOR(FmSearchEngine,NULL);
765 fillControlTexts(arrFields);
766 Init(sVisibleFields);
769 //------------------------------------------------------------------------
770 FmSearchEngine::~FmSearchEngine()
772 clearControlTexts();
774 DBG_DTOR(FmSearchEngine,NULL);
777 //------------------------------------------------------------------------
778 void FmSearchEngine::SetIgnoreWidthCJK(sal_Bool bSet)
780 if (bSet)
781 m_nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH;
782 else
783 m_nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH;
786 //------------------------------------------------------------------------
787 sal_Bool FmSearchEngine::GetIgnoreWidthCJK() const
789 return 0 != (m_nTransliterationFlags & TransliterationModules_IGNORE_WIDTH);
792 //------------------------------------------------------------------------
793 void FmSearchEngine::SetCaseSensitive(sal_Bool bSet)
795 if (bSet)
796 m_nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE;
797 else
798 m_nTransliterationFlags |= TransliterationModules_IGNORE_CASE;
801 //------------------------------------------------------------------------
802 sal_Bool FmSearchEngine::GetCaseSensitive() const
804 return 0 == (m_nTransliterationFlags & TransliterationModules_IGNORE_CASE);
807 //------------------------------------------------------------------------
808 void FmSearchEngine::clearControlTexts()
810 for ( ControlTextSuppliersIterator aIter = m_aControlTexts.begin();
811 aIter < m_aControlTexts.end();
812 ++aIter
815 delete *aIter;
817 m_aControlTexts.clear();
820 //------------------------------------------------------------------------
821 void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields)
823 clearControlTexts();
824 Reference< XInterface > xCurrent;
825 for (sal_uInt32 i=0; i<arrFields.size(); ++i)
827 xCurrent = arrFields.at(i);
828 DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !");
829 // check which type of control this is
830 Reference< ::com::sun::star::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY);
831 if (xAsText.is())
833 m_aControlTexts.insert(m_aControlTexts.end(), new SimpleTextWrapper(xAsText));
834 continue;
837 Reference< ::com::sun::star::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY);
838 if (xAsListBox.is())
840 m_aControlTexts.insert(m_aControlTexts.end(), new ListBoxWrapper(xAsListBox));
841 continue;
844 Reference< ::com::sun::star::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY);
845 DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !");
846 // we don't have any more options ...
847 m_aControlTexts.insert(m_aControlTexts.end(), new CheckBoxWrapper(xAsCheckBox));
851 //------------------------------------------------------------------------
852 void FmSearchEngine::Init(const ::rtl::OUString& sVisibleFields)
854 // analyze the fields
855 // additionally, create the mapping: because the list of used columns can be shorter than the list
856 // of columns of the cursor, we need a mapping: "used column numer n" -> "cursor column m"
857 m_arrFieldMapping.Remove(0, m_arrFieldMapping.Count());
859 // important: The case of the columns does not need to be exact - for instance:
860 // - a user created a form which works on a table, for which the driver returns a column name "COLUMN"
861 // - the driver itself works case-insensitve with column names
862 // - a control in the form is bound to "column" - not the different case
863 // In such a scenario, the form and the field would work okay, but we here need to case for the different case
864 // explicitly
865 // 2003-01-09 - #i8755# - fs@openoffice.org
867 // so first of all, check if the database handles identifiers case sensitive
868 Reference< XConnection > xConn;
869 Reference< XDatabaseMetaData > xMeta;
870 Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY );
871 if ( xCursorProps.is() )
875 xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn;
877 catch( Exception& ) { /* silent this - will be asserted below */ }
879 if ( xConn.is() )
880 xMeta = xConn->getMetaData();
881 OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" );
883 sal_Bool bCaseSensitiveIdentifiers = sal_True; // assume case sensivity
884 if ( xMeta.is() )
885 bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers();
887 // now that we have this information, we need a collator which is able to case (in)sentively compare strings
888 m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLocaleData().getLocale(),
889 bCaseSensitiveIdentifiers ? 0 : ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
893 // der Cursor kann mir einen Record (als PropertySet) liefern, dieser unterstuetzt den DatabaseRecord-Service
894 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
895 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !");
896 Reference< ::com::sun::star::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns();
897 Sequence< ::rtl::OUString > seqFieldNames = xAllFieldNames->getElementNames();
898 ::rtl::OUString* pFieldNames = seqFieldNames.getArray();
901 ::rtl::OUString sCurrentField;
902 UniString sVis(sVisibleFields.getStr());
903 xub_StrLen nLen = sVis.GetTokenCount();
904 for (xub_StrLen i=0; i<nLen; ++i)
906 sCurrentField = sVis.GetToken(i);
908 // in der Feld-Sammlung suchen
909 sal_Int32 nFoundIndex = -1;
910 for (sal_Int32 j=0; j<seqFieldNames.getLength(); ++j, ++pFieldNames)
912 if ( 0 == m_aStringCompare.compareString( *pFieldNames, sCurrentField ) )
914 nFoundIndex = j;
915 break;
918 // set the field selection back to the first
919 pFieldNames = seqFieldNames.getArray();;
920 DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Es wurden ungueltige Feldnamen angegeben !");
921 m_arrFieldMapping.Insert(nFoundIndex, m_arrFieldMapping.Count());
924 catch(Exception&)
926 DBG_ERROR("Exception occured!");
931 //------------------------------------------------------------------------
932 void FmSearchEngine::SetFormatterUsing(sal_Bool bSet)
934 if (m_bFormatter == bSet)
935 return;
936 m_bFormatter = bSet;
938 if (m_bUsingTextComponents)
940 // ich benutzte keinen Formatter, sondern TextComponents -> der SearchIterator muss angepasst werden
943 if (m_bFormatter)
945 DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
946 m_xSearchCursor = m_xOriginalIterator;
947 m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark());
948 // damit ich mit dem neuen Iterator wirklich dort weitermache, wo ich vorher aufgehoert habe
950 else
952 DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !");
953 m_xSearchCursor = m_xClonedIterator;
954 m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark());
957 catch( const Exception& )
959 DBG_UNHANDLED_EXCEPTION();
962 // ich muss die Fields neu binden, da der Textaustausch eventuell ueber diese Fields erfolgt und sich der unterliegende Cursor
963 // geaendert hat
964 RebuildUsedFields(m_nCurrentFieldIndex, sal_True);
966 else
967 InvalidatePreviousLoc();
970 //------------------------------------------------------------------------
971 void FmSearchEngine::PropagateProgress(sal_Bool _bDontPropagateOverflow)
973 if (m_aProgressHandler.IsSet())
975 FmSearchProgress aProgress;
978 aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS;
979 aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
980 if (m_bForward)
981 aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst();
982 else
983 aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast();
985 catch( const Exception& )
987 DBG_UNHANDLED_EXCEPTION();
990 m_aProgressHandler.Call(&aProgress);
994 //------------------------------------------------------------------------
995 void FmSearchEngine::SearchNextImpl()
997 DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard),
998 "FmSearchEngine::SearchNextImpl : Suchparameter schliessen sich gegenseitig aus !");
1000 DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : habe ungueltigen Iterator !");
1002 // die Parameter der Suche
1003 ::rtl::OUString strSearchExpression(m_strSearchExpression); // brauche ich non-const
1004 if (!GetCaseSensitive())
1005 // norm the string
1006 m_aCharacterClassficator.toLower_rtl(strSearchExpression);
1008 if (!m_bRegular && !m_bLevenshtein)
1009 { // 'normale' Suche fuehre ich auf jeden Fall ueber WildCards durch, muss aber vorher je nach Modus den ::rtl::OUString anpassen
1011 if (!m_bWildcard)
1012 { // da natuerlich in allen anderen Faellen auch * und ? im Suchstring erlaubt sind, aber nicht als WildCards zaehlen
1013 // sollen, muss ich normieren
1014 UniString aTmp(strSearchExpression.getStr());
1015 static const UniString s_sStar = UniString::CreateFromAscii("\\*");
1016 static const UniString s_sQuotation = UniString::CreateFromAscii("\\?");
1017 aTmp.SearchAndReplaceAll('*', s_sStar);
1018 aTmp.SearchAndReplaceAll('?', s_sQuotation);
1019 strSearchExpression = aTmp;
1021 switch (m_nPosition)
1023 case MATCHING_ANYWHERE :
1024 strSearchExpression = ::rtl::OUString::createFromAscii("*") + strSearchExpression
1025 + ::rtl::OUString::createFromAscii("*");
1026 break;
1027 case MATCHING_BEGINNING :
1028 strSearchExpression = strSearchExpression + ::rtl::OUString::createFromAscii("*");
1029 break;
1030 case MATCHING_END :
1031 strSearchExpression = ::rtl::OUString::createFromAscii("*") + strSearchExpression;
1032 break;
1033 case MATCHING_WHOLETEXT :
1034 break;
1035 default :
1036 DBG_ERROR("FmSearchEngine::SearchNextImpl() : die Methoden-Listbox duerfte nur 4 Eintraege enthalten ...");
1041 // fuer Arbeit auf Feldliste
1042 FieldCollectionIterator iterBegin = m_arrUsedFields.begin();
1043 FieldCollectionIterator iterEnd = m_arrUsedFields.end();
1044 FieldCollectionIterator iterFieldCheck;
1046 sal_Int32 nFieldPos;
1048 if (HasPreviousLoc())
1050 DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()),
1051 "FmSearchEngine::SearchNextImpl : ungueltige Position !");
1052 iterFieldCheck = m_iterPreviousLocField;
1053 // im Feld nach (oder vor) der letzten Fundstelle weitermachen
1054 nFieldPos = iterFieldCheck - iterBegin;
1055 MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1057 else
1059 if (m_bForward)
1060 iterFieldCheck = iterBegin;
1061 else
1063 iterFieldCheck = iterEnd;
1064 --iterFieldCheck;
1066 nFieldPos = iterFieldCheck - iterBegin;
1069 PropagateProgress(sal_True);
1070 SEARCH_RESULT srResult;
1071 if (m_eSearchForType != SEARCHFOR_STRING)
1072 srResult = SearchSpecial(m_eSearchForType == SEARCHFOR_NULL, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1073 else if (!m_bRegular && !m_bLevenshtein)
1074 srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1075 else
1076 srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
1078 m_srResult = srResult;
1080 if (SR_ERROR == m_srResult)
1081 return;
1083 // gefunden ?
1084 if (SR_FOUND == m_srResult)
1086 // die Pos merken
1087 try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
1088 catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
1089 m_iterPreviousLocField = iterFieldCheck;
1091 else
1092 // die "letzte Fundstelle" invalidieren
1093 InvalidatePreviousLoc();
1096 //------------------------------------------------------------------------
1097 IMPL_LINK(FmSearchEngine, OnSearchTerminated, FmSearchThread*, /*pThread*/)
1099 if (!m_aProgressHandler.IsSet())
1100 return 0L;
1102 FmSearchProgress aProgress;
1105 switch (m_srResult)
1107 case SR_ERROR :
1108 aProgress.aSearchState = FmSearchProgress::STATE_ERROR;
1109 break;
1110 case SR_FOUND :
1111 aProgress.aSearchState = FmSearchProgress::STATE_SUCCESSFULL;
1112 aProgress.aBookmark = m_aPreviousLocBookmark;
1113 aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin();
1114 break;
1115 case SR_NOTFOUND :
1116 aProgress.aSearchState = FmSearchProgress::STATE_NOTHINGFOUND;
1117 aProgress.aBookmark = m_xSearchCursor.getBookmark();
1118 break;
1119 case SR_CANCELED :
1120 aProgress.aSearchState = FmSearchProgress::STATE_CANCELED;
1121 aProgress.aBookmark = m_xSearchCursor.getBookmark();
1122 break;
1124 aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
1126 catch( const Exception& )
1128 DBG_UNHANDLED_EXCEPTION();
1131 // per definitionem muss der Link Thread-sicher sein (das verlange ich einfach), so dass ich mich um so etwas hier nicht kuemmern muss
1132 m_aProgressHandler.Call(&aProgress);
1134 m_bSearchingCurrently = sal_False;
1135 return 0L;
1138 //------------------------------------------------------------------------
1139 IMPL_LINK(FmSearchEngine, OnNewRecordCount, void*, pCounterAsVoid)
1141 if (!m_aProgressHandler.IsSet())
1142 return 0L;
1144 FmSearchProgress aProgress;
1145 aProgress.nCurrentRecord = (sal_uIntPtr)pCounterAsVoid;
1146 aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS_COUNTING;
1147 m_aProgressHandler.Call(&aProgress);
1149 return 0L;
1152 //------------------------------------------------------------------------
1153 sal_Bool FmSearchEngine::CancelRequested()
1155 m_aCancelAsynchAccess.acquire();
1156 sal_Bool bReturn = m_bCancelAsynchRequest;
1157 m_aCancelAsynchAccess.release();
1158 return bReturn;
1161 //------------------------------------------------------------------------
1162 void FmSearchEngine::CancelSearch()
1164 m_aCancelAsynchAccess.acquire();
1165 m_bCancelAsynchRequest = sal_True;
1166 m_aCancelAsynchAccess.release();
1169 //------------------------------------------------------------------------
1170 sal_Bool FmSearchEngine::SwitchToContext(const Reference< ::com::sun::star::sdbc::XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, const InterfaceArray& arrFields,
1171 sal_Int32 nFieldIndex)
1173 DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !");
1174 if (m_bSearchingCurrently)
1175 return sal_False;
1177 m_xSearchCursor = xCursor;
1178 m_xOriginalIterator = xCursor;
1179 m_xClonedIterator = CursorWrapper(m_xOriginalIterator, sal_True);
1180 m_bUsingTextComponents = sal_True;
1182 fillControlTexts(arrFields);
1184 Init(sVisibleFields);
1185 RebuildUsedFields(nFieldIndex, sal_True);
1187 return sal_True;
1190 //------------------------------------------------------------------------
1191 void FmSearchEngine::ImplStartNextSearch()
1193 m_bCancelAsynchRequest = sal_False;
1194 m_bSearchingCurrently = sal_True;
1196 if (m_eMode == SM_USETHREAD)//CHINA001 if (m_eMode == FmSearchDialog::SM_USETHREAD)
1198 FmSearchThread* pSearcher = new FmSearchThread(this);
1199 // der loescht sich nach Beendigung selber ...
1200 pSearcher->setTerminationHandler(LINK(this, FmSearchEngine, OnSearchTerminated));
1202 pSearcher->createSuspended();
1203 pSearcher->setPriority(::vos::OThread::TPriority_Lowest);
1204 pSearcher->resume();
1206 else
1208 SearchNextImpl();
1209 LINK(this, FmSearchEngine, OnSearchTerminated).Call(NULL);
1213 //------------------------------------------------------------------------
1214 void FmSearchEngine::SearchNext(const ::rtl::OUString& strExpression)
1216 m_strSearchExpression = strExpression;
1217 m_eSearchForType = SEARCHFOR_STRING;
1218 ImplStartNextSearch();
1221 //------------------------------------------------------------------------
1222 void FmSearchEngine::SearchNextSpecial(sal_Bool _bSearchForNull)
1224 m_eSearchForType = _bSearchForNull ? SEARCHFOR_NULL : SEARCHFOR_NOTNULL;
1225 ImplStartNextSearch();
1228 //------------------------------------------------------------------------
1229 void FmSearchEngine::StartOver(const ::rtl::OUString& strExpression)
1233 if (m_bForward)
1234 m_xSearchCursor.first();
1235 else
1236 m_xSearchCursor.last();
1238 catch( const Exception& )
1240 DBG_UNHANDLED_EXCEPTION();
1241 return;
1244 InvalidatePreviousLoc();
1245 SearchNext(strExpression);
1248 //------------------------------------------------------------------------
1249 void FmSearchEngine::StartOverSpecial(sal_Bool _bSearchForNull)
1253 if (m_bForward)
1254 m_xSearchCursor.first();
1255 else
1256 m_xSearchCursor.last();
1258 catch( const Exception& )
1260 DBG_UNHANDLED_EXCEPTION();
1261 return;
1264 InvalidatePreviousLoc();
1265 SearchNextSpecial(_bSearchForNull);
1268 //------------------------------------------------------------------------
1269 void FmSearchEngine::InvalidatePreviousLoc()
1271 m_aPreviousLocBookmark.setValue(0,getVoidCppuType());
1272 m_iterPreviousLocField = m_arrUsedFields.end();
1275 //------------------------------------------------------------------------
1276 void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, sal_Bool bForce)
1278 if (!bForce && (nFieldIndex == m_nCurrentFieldIndex))
1279 return;
1280 // (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)
1282 DBG_ASSERT((nFieldIndex >= -1) && (nFieldIndex<m_arrFieldMapping.Count()), "FmSearchEngine::RebuildUsedFields : nFieldIndex ist ungueltig !");
1283 // alle Felder, die ich durchsuchen muss, einsammeln
1284 m_arrUsedFields.clear();
1285 if (nFieldIndex == -1)
1287 Reference< ::com::sun::star::container::XIndexAccess > xFields;
1288 for (sal_uInt16 i=0; i<m_arrFieldMapping.Count(); ++i)
1290 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 xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
1293 BuildAndInsertFieldInfo(xFields, m_arrFieldMapping.GetObject(i));
1296 else
1298 Reference< ::com::sun::star::container::XIndexAccess > xFields;
1299 Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1300 DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1301 xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY);
1302 BuildAndInsertFieldInfo(xFields, m_arrFieldMapping.GetObject((sal_uInt16)nFieldIndex));
1305 m_nCurrentFieldIndex = nFieldIndex;
1306 // und natuerlich beginne ich die naechste Suche wieder jungfraeulich
1307 InvalidatePreviousLoc();