LCOV - code coverage report
Current view: top level - svx/source/form - fmsrcimp.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 531 0.2 %
Date: 2014-11-03 Functions: 2 54 3.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10