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

Generated by: LCOV version 1.10