diff options
Diffstat (limited to 'svx/source/form/fmsrcimp.cxx')
-rw-r--r-- | svx/source/form/fmsrcimp.cxx | 1301 |
1 files changed, 1301 insertions, 0 deletions
diff --git a/svx/source/form/fmsrcimp.cxx b/svx/source/form/fmsrcimp.cxx new file mode 100644 index 000000000000..ee870f0c29b0 --- /dev/null +++ b/svx/source/form/fmsrcimp.cxx @@ -0,0 +1,1301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#ifndef _SVX_FMRESIDS_HRC +#include "fmresids.hrc" +#endif +#include "svx/fmtools.hxx" +#include "fmsrccfg.hxx" +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/wldcrd.hxx> +#include <vcl/msgbox.hxx> +#include <tools/shl.hxx> +#include <svx/dialmgr.hxx> +#include <cppuhelper/servicefactory.hxx> +#include <vcl/svapp.hxx> +#include <unotools/textsearch.hxx> +#include <com/sun/star/util/SearchOptions.hpp> +#include <com/sun/star/util/SearchAlgorithms.hpp> +#include <com/sun/star/util/SearchResult.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/i18n/TransliterationModules.hpp> +#include <com/sun/star/i18n/CollatorOptions.hpp> + +#ifndef _COM_SUN_STAR_SDDB_XCOLUMNSSUPPLIER_HPP_ +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#endif +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <comphelper/processfactory.hxx> + +#ifndef _SVX_FMPROP_HRC +#include "fmprop.hrc" +#endif +#include "fmservs.hxx" +#include "fmsrcimp.hxx" +#include <svx/fmsearch.hxx> + +#include <comphelper/numbers.hxx> +#include <unotools/syslocale.hxx> + +#define EQUAL_BOOKMARKS(a, b) a == b + +#define IFACECAST(c) ((const Reference< XInterface >&)c) + // SUN C52 has some ambiguities without this cast .... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::beans; +using namespace ::svxform; + + +//======================================================================== +// = FmSearchThread +//------------------------------------------------------------------------ +void FmSearchThread::run() +{ + m_pEngine->SearchNextImpl(); +}; + +//------------------------------------------------------------------------ +void FmSearchThread::onTerminated() +{ + if (m_aTerminationHdl.IsSet()) + m_aTerminationHdl.Call(this); + delete this; +} + +//======================================================================== +// = FmRecordCountListener + +// SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject); + +DBG_NAME(FmRecordCountListener); +//------------------------------------------------------------------------ +FmRecordCountListener::FmRecordCountListener(const Reference< ::com::sun::star::sdbc::XResultSet > & dbcCursor) +{ + DBG_CTOR(FmRecordCountListener,NULL); + + m_xListening = Reference< ::com::sun::star::beans::XPropertySet > (dbcCursor, UNO_QUERY); + if (!m_xListening.is()) + return; + + if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL))) + { + m_xListening = NULL; + // there's nothing to do as the record count is already known + return; + } + + m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this); +} + +//------------------------------------------------------------------------ +Link FmRecordCountListener::SetPropChangeHandler(const Link& lnk) +{ + Link lnkReturn = m_lnkWhoWantsToKnow; + m_lnkWhoWantsToKnow = lnk; + + if (m_xListening.is()) + NotifyCurrentCount(); + + return lnkReturn; +} + +//------------------------------------------------------------------------ +FmRecordCountListener::~FmRecordCountListener() +{ + + DBG_DTOR(FmRecordCountListener,NULL); +} + +//------------------------------------------------------------------------ +void FmRecordCountListener::DisConnect() +{ + if(m_xListening.is()) + m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this); + m_xListening = NULL; +} + +//------------------------------------------------------------------------ +void SAL_CALL FmRecordCountListener::disposing(const ::com::sun::star::lang::EventObject& /*Source*/) throw( RuntimeException ) +{ + DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !"); + DisConnect(); +} + +//------------------------------------------------------------------------ +void FmRecordCountListener::NotifyCurrentCount() +{ + if (m_lnkWhoWantsToKnow.IsSet()) + { + DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?"); + void* pTheCount = (void*)::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT)); + m_lnkWhoWantsToKnow.Call(pTheCount); + } +} + +//------------------------------------------------------------------------ +void FmRecordCountListener::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& /*evt*/) throw(::com::sun::star::uno::RuntimeException) +{ + NotifyCurrentCount(); +} + +//======================================================================== +// FmSearchEngine - local classes +//------------------------------------------------------------------------ +SimpleTextWrapper::SimpleTextWrapper(const Reference< ::com::sun::star::awt::XTextComponent > & _xText) + :ControlTextWrapper(_xText.get()) + ,m_xText(_xText) +{ + DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !"); +} + +//------------------------------------------------------------------------ +::rtl::OUString SimpleTextWrapper::getCurrentText() const +{ + return m_xText->getText(); +} + +//------------------------------------------------------------------------ +ListBoxWrapper::ListBoxWrapper(const Reference< ::com::sun::star::awt::XListBox > & _xBox) + :ControlTextWrapper(_xBox.get()) + ,m_xBox(_xBox) +{ + DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !"); +} + +//------------------------------------------------------------------------ +::rtl::OUString ListBoxWrapper::getCurrentText() const +{ + return m_xBox->getSelectedItem(); +} + +//------------------------------------------------------------------------ +CheckBoxWrapper::CheckBoxWrapper(const Reference< ::com::sun::star::awt::XCheckBox > & _xBox) + :ControlTextWrapper(_xBox.get()) + ,m_xBox(_xBox) +{ + DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !"); +} + +//------------------------------------------------------------------------ +::rtl::OUString CheckBoxWrapper::getCurrentText() const +{ + switch ((TriState)m_xBox->getState()) + { + case STATE_NOCHECK: return rtl::OUString::createFromAscii("0"); + case STATE_CHECK: return rtl::OUString::createFromAscii("1"); + default: break; + } + return rtl::OUString(); +} + +//======================================================================== +// = FmSearchEngine +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::MoveCursor() +{ + sal_Bool bSuccess = sal_True; + try + { + if (m_bForward) + if (m_xSearchCursor.isLast()) + m_xSearchCursor.first(); + else + m_xSearchCursor.next(); + else + if (m_xSearchCursor.isFirst()) + { + FmRecordCountListener* prclListener = new FmRecordCountListener(m_xSearchCursor); + prclListener->acquire(); + prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount)); + + m_xSearchCursor.last(); + + prclListener->DisConnect(); + prclListener->release(); + } + else + m_xSearchCursor.previous(); + } + catch(::com::sun::star::sdbc::SQLException e) + { +#if OSL_DEBUG_LEVEL > 0 + String sDebugMessage; + sDebugMessage.AssignAscii("FmSearchEngine::MoveCursor : catched a DatabaseException ("); + sDebugMessage += (const sal_Unicode*)e.SQLState; + sDebugMessage.AppendAscii(") !"); + DBG_ERROR(ByteString(sDebugMessage, RTL_TEXTENCODING_ASCII_US).GetBuffer()); +#endif + bSuccess = sal_False; + } + catch(Exception e) + { +#if OSL_DEBUG_LEVEL > 0 + UniString sDebugMessage; + sDebugMessage.AssignAscii("FmSearchEngine::MoveCursor : catched an Exception ("); + sDebugMessage += (const sal_Unicode*)e.Message; + sDebugMessage.AppendAscii(") !"); + DBG_ERROR(ByteString(sDebugMessage, RTL_TEXTENCODING_ASCII_US).GetBuffer()); +#endif + bSuccess = sal_False; + } + catch(...) + { + DBG_ERROR("FmSearchEngine::MoveCursor : catched an unknown Exception !"); + bSuccess = sal_False; + } + + return bSuccess; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollectionIterator& iter, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + sal_Bool bSuccess(sal_True); + if (m_bForward) + { + ++iter; + ++nPos; + if (iter == iterEnd) + { + bSuccess = MoveCursor(); + iter = iterBegin; + nPos = 0; + } + } else + { + if (iter == iterBegin) + { + bSuccess = MoveCursor(); + iter = iterEnd; + nPos = iter-iterBegin; + } + --iter; + --nPos; + } + return bSuccess; +} + +//------------------------------------------------------------------------ +void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< ::com::sun::star::container::XIndexAccess > & xAllFields, sal_Int32 nField) +{ + DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ), + "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" ); + + // das Feld selber + Reference< XInterface > xCurrentField; + xAllFields->getByIndex(nField) >>= xCurrentField; + + // von dem weiss ich jetzt, dass es den DatabaseRecord-Service unterstuetzt (hoffe ich) + // fuer den FormatKey und den Typ brauche ich das PropertySet + Reference< ::com::sun::star::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY); + + // die FieldInfo dazu aufbauen + FieldInfo fiCurrent; + fiCurrent.xContents = Reference< ::com::sun::star::sdb::XColumn > (xCurrentField, UNO_QUERY); + fiCurrent.nFormatKey = ::comphelper::getINT32(xProperties->getPropertyValue(FM_PROP_FORMATKEY)); + fiCurrent.bDoubleHandling = sal_False; + if (m_xFormatSupplier.is()) + { + Reference< ::com::sun::star::util::XNumberFormats > xNumberFormats(m_xFormatSupplier->getNumberFormats()); + + sal_Int16 nFormatType = ::comphelper::getNumberFormatType(xNumberFormats, fiCurrent.nFormatKey) & ~((sal_Int16)::com::sun::star::util::NumberFormat::DEFINED); + fiCurrent.bDoubleHandling = (nFormatType != ::com::sun::star::util::NumberFormat::TEXT); + } + + // und merken + m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent); + +} +//------------------------------------------------------------------------ +::rtl::OUString FmSearchEngine::FormatField(const FieldInfo& rField) +{ + DBG_ASSERT(!m_bUsingTextComponents, "FmSearchEngine::FormatField : im UsingTextComponents-Mode bitte FormatField(sal_Int32) benutzen !"); + + if (!m_xFormatter.is()) + return ::rtl::OUString(); + // sonst werden Datumsflder zum Beispiel zu irgendeinem Default-Wert formatiert + + ::rtl::OUString sReturn; + try + { + if (rField.bDoubleHandling) + { + double fValue = rField.xContents->getDouble(); + if (!rField.xContents->wasNull()) + sReturn = m_xFormatter->convertNumberToString(rField.nFormatKey, fValue); + } + else + { + ::rtl::OUString sValue = rField.xContents->getString(); + if (!rField.xContents->wasNull()) + sReturn = m_xFormatter->formatString(rField.nFormatKey, sValue); + } + } + catch(...) + { + } + + + return sReturn; +} + +//------------------------------------------------------------------------ +::rtl::OUString FmSearchEngine::FormatField(sal_Int32 nWhich) +{ + if (m_bUsingTextComponents) + { + DBG_ASSERT((sal_uInt32)nWhich < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !"); + DBG_ASSERT(m_aControlTexts[nWhich] != NULL, "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !"); + DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !"); + + if (m_nCurrentFieldIndex != -1) + { + DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig"); + // analoge Situation wie unten + nWhich = m_nCurrentFieldIndex; + } + + DBG_ASSERT((nWhich >= 0) && ((sal_uInt32)nWhich < m_aControlTexts.size()), + "FmSearchEngine::FormatField : invalid argument nWhich !"); + return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText(); + } + else + { + if (m_nCurrentFieldIndex != -1) + { + DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig"); + // ich bin im single-field-modus, da ist auch die richtige Feld-Nummer erlaubt, obwohl dann der richtige ::com::sun::star::sdbcx::Index + // fuer meinen Array-Zugriff natuerlich 0 ist + nWhich = 0; + } + + DBG_ASSERT((nWhich>=0) && (nWhich < (m_arrUsedFields.end() - m_arrUsedFields.begin())), + "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig"); + return FormatField(m_arrUsedFields[nWhich]); + } +} + +//------------------------------------------------------------------------ +FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchSpecial(sal_Bool _bSearchForNull, sal_Int32& nFieldPos, + FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + // die Startposition merken + Any aStartMark; + try { aStartMark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + FieldCollectionIterator iterInitialField = iterFieldLoop; + + // -------------------------------------------------------------- + sal_Bool bFound(sal_False); + sal_Bool bMovedAround(sal_False); + do + { + if (m_eMode == SM_ALLOWSCHEDULE) //CHINA001 if (m_eMode == FmSearchDialog::SM_ALLOWSCHEDULE) + { + Application::Reschedule(); + Application::Reschedule(); + // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event + // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings + // or anything like that. So within each loop we create one user event and handle one user event (and no + // paintings and these), so the office seems to be frozen while searching. + // FS - 70226 - 02.12.99 + } + + // der aktuell zu vergleichende Inhalt + iterFieldLoop->xContents->getString(); // needed for wasNull + bFound = _bSearchForNull == iterFieldLoop->xContents->wasNull(); + if (bFound) + break; + + // naechstes Feld (implizit naechster Datensatz, wenn noetig) + if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd)) + { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau + // das selbe bestimmt wieder schief geht, also Abbruch + // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht : + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldLoop; + // und wech + return SR_ERROR; + } + + Any aCurrentBookmark; + try { aCurrentBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + + bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField); + + if (nFieldPos == 0) + // das heisst, ich habe mich auf einen neuen Datensatz bewegt + PropagateProgress(bMovedAround); + // if we moved to the starting position we don't have to propagate an 'overflow' message + // FS - 07.12.99 - 68530 + + // abbrechen gefordert ? + if (CancelRequested()) + return SR_CANCELED; + + } while (!bMovedAround); + + return bFound ? SR_FOUND : SR_NOTFOUND; +} + +//------------------------------------------------------------------------ +FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchWildcard(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos, + FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + // die Startposition merken + Any aStartMark; + try { aStartMark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + FieldCollectionIterator iterInitialField = iterFieldLoop; + + WildCard aSearchExpression(strExpression); + + // -------------------------------------------------------------- + sal_Bool bFound(sal_False); + sal_Bool bMovedAround(sal_False); + do + { + if (m_eMode == SM_ALLOWSCHEDULE) //CHINA001 if (m_eMode == FmSearchDialog::SM_ALLOWSCHEDULE) + { + Application::Reschedule(); + Application::Reschedule(); + // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event + // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings + // or anything like that. So within each loop we create one user event and hanel one user event (and no + // paintings and these), so the office seems to be frozen while searching. + // FS - 70226 - 02.12.99 + } + + // der aktuell zu vergleichende Inhalt + ::rtl::OUString sCurrentCheck; + if (m_bFormatter) + sCurrentCheck = FormatField(nFieldPos); + else + sCurrentCheck = iterFieldLoop->xContents->getString(); + + if (!GetCaseSensitive()) + // norm the string + m_aCharacterClassficator.toLower_rtl(sCurrentCheck); + + // jetzt ist der Test einfach ... + bFound = aSearchExpression.Matches(sCurrentCheck); + + if (bFound) + break; + + // naechstes Feld (implizit naechster Datensatz, wenn noetig) + if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd)) + { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau + // das selbe bestimmt wieder schief geht, also Abbruch + // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht : + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldLoop; + // und wech + return SR_ERROR; + } + + Any aCurrentBookmark; + try { aCurrentBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + + bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField); + + if (nFieldPos == 0) + // das heisst, ich habe mich auf einen neuen Datensatz bewegt + PropagateProgress(bMovedAround); + // if we moved to the starting position we don't have to propagate an 'overflow' message + // FS - 07.12.99 - 68530 + + // abbrechen gefordert ? + if (CancelRequested()) + return SR_CANCELED; + + } while (!bMovedAround); + + return bFound ? SR_FOUND : SR_NOTFOUND; +} + +//------------------------------------------------------------------------ +FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchRegularApprox(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos, + FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + DBG_ASSERT(m_bLevenshtein || m_bRegular, + "FmSearchEngine::SearchRegularApprox : ungueltiger Suchmodus !"); + DBG_ASSERT(!m_bLevenshtein || !m_bRegular, + "FmSearchEngine::SearchRegularApprox : kann nicht nach regulaeren Ausdruecken und nach Aehnlichkeiten gleichzeitig suchen !"); + + // Startposition merken + Any aStartMark; + try { aStartMark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + FieldCollectionIterator iterInitialField = iterFieldLoop; + + // Parameter sammeln + SearchOptions aParam; + aParam.algorithmType = m_bRegular ? SearchAlgorithms_REGEXP : SearchAlgorithms_APPROXIMATE; + aParam.searchFlag = 0; + aParam.transliterateFlags = GetTransliterationFlags(); + if ( !GetTransliteration() ) + { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH + aParam.transliterateFlags &= TransliterationModules_IGNORE_CASE | TransliterationModules_IGNORE_WIDTH; + } + if (m_bLevenshtein) + { + if (m_bLevRelaxed) + aParam.searchFlag |= SearchFlags::LEV_RELAXED; + aParam.changedChars = m_nLevOther; + aParam.deletedChars = m_nLevShorter; + aParam.insertedChars = m_nLevLonger; + } + aParam.searchString = strExpression; + aParam.Locale = SvtSysLocale().GetLocaleData().getLocale(); + ::utl::TextSearch aLocalEngine(aParam); + + // -------------------------------------------------------------- + bool bFound = false; + sal_Bool bMovedAround(sal_False); + do + { + if (m_eMode == SM_ALLOWSCHEDULE) //CHINA001 if (m_eMode == FmSearchDialog::SM_ALLOWSCHEDULE) + { + Application::Reschedule(); + Application::Reschedule(); + // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event + // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings + // or anything like that. So within each loop we create one user event and handle one user event (and no + // paintings and these), so the office seems to be frozen while searching. + // FS - 70226 - 02.12.99 + } + + // der aktuell zu vergleichende Inhalt + ::rtl::OUString sCurrentCheck; + if (m_bFormatter) + sCurrentCheck = FormatField(nFieldPos); + else + sCurrentCheck = iterFieldLoop->xContents->getString(); + + // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it) + + xub_StrLen nStart = 0, nEnd = (xub_StrLen)sCurrentCheck.getLength(); + bFound = aLocalEngine.SearchFrwrd(sCurrentCheck, &nStart, &nEnd); + // das heisst hier 'forward' aber das bezieht sich nur auf die Suche innerhalb von sCurrentCheck, hat also mit + // der Richtung meines Datensatz-Durchwanderns nix zu tun (darum kuemmert sich MoveField) + + // checken, ob die Position stimmt + if (bFound) + { + switch (m_nPosition) + { + case MATCHING_WHOLETEXT : + if (nEnd != sCurrentCheck.getLength()) + { + bFound = false; + break; + } + // laeuft in den naechsten Case rein ! + case MATCHING_BEGINNING : + if (nStart != 0) + bFound = false; + break; + case MATCHING_END : + if (nEnd != sCurrentCheck.getLength()) + bFound = false; + break; + } + } + + if (bFound) // immer noch ? + break; + + // naechstes Feld (implizit naechster Datensatz, wenn noetig) + if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd)) + { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau + // das selbe bestimmt wieder schief geht, also Abbruch (ohne Fehlermeldung, von der erwarte ich, dass sie im Move + // angezeigt wurde) + // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht : + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldLoop; + // und wech + return SR_ERROR; + } + + Any aCurrentBookmark; + try { aCurrentBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField); + + if (nFieldPos == 0) + // das heisst, ich habe mich auf einen neuen Datensatz bewegt + PropagateProgress(bMovedAround); + // if we moved to the starting position we don't have to propagate an 'overflow' message + // FS - 07.12.99 - 68530 + + // abbrechen gefordert ? + if (CancelRequested()) + return SR_CANCELED; + + } while (!bMovedAround); + + return bFound ? SR_FOUND : SR_NOTFOUND; +} + + +DBG_NAME(FmSearchEngine); +//------------------------------------------------------------------------ +FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, + const Reference< XNumberFormatsSupplier > & xFormatSupplier, FMSEARCH_MODE eMode)//CHINA001 const Reference< XNumberFormatsSupplier > & xFormatSupplier, FmSearchDialog::SEARCH_MODE eMode) + :m_xSearchCursor(xCursor) + ,m_xFormatSupplier(xFormatSupplier) + ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() ) + ,m_aStringCompare( _rxORB ) + ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig' + ,m_bUsingTextComponents(sal_False) + ,m_eSearchForType(SEARCHFOR_STRING) + ,m_srResult(SR_FOUND) + ,m_bSearchingCurrently(sal_False) + ,m_bCancelAsynchRequest(sal_False) + ,m_eMode(eMode) + ,m_bFormatter(sal_False) + ,m_bForward(sal_False) + ,m_bWildcard(sal_False) + ,m_bRegular(sal_False) + ,m_bLevenshtein(sal_False) + ,m_bTransliteration(sal_False) + ,m_bLevRelaxed(sal_False) + ,m_nLevOther(0) + ,m_nLevShorter(0) + ,m_nLevLonger(0) + ,m_nPosition(MATCHING_ANYWHERE) + ,m_nTransliterationFlags(0) +{ + DBG_CTOR(FmSearchEngine,NULL); + + m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter > (::comphelper::getProcessServiceFactory() + ->createInstance(FM_NUMBER_FORMATTER), UNO_QUERY); + if (m_xFormatter.is()) + m_xFormatter->attachNumberFormatsSupplier(m_xFormatSupplier); + + Init(sVisibleFields); +} + +//------------------------------------------------------------------------ +FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, + const InterfaceArray& arrFields, FMSEARCH_MODE eMode)//CHINA001 const InterfaceArray& arrFields, FmSearchDialog::SEARCH_MODE eMode) + :m_xSearchCursor(xCursor) + ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() ) + ,m_aStringCompare( _rxORB ) + ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig' + ,m_bUsingTextComponents(sal_True) + ,m_xOriginalIterator(xCursor) + ,m_xClonedIterator(m_xOriginalIterator, sal_True) + ,m_eSearchForType(SEARCHFOR_STRING) + ,m_srResult(SR_FOUND) + ,m_bSearchingCurrently(sal_False) + ,m_bCancelAsynchRequest(sal_False) + ,m_eMode(eMode) + ,m_bFormatter(sal_True) // das muss konsistent sein mit m_xSearchCursor, der i.A. == m_xOriginalIterator ist + ,m_bForward(sal_False) + ,m_bWildcard(sal_False) + ,m_bRegular(sal_False) + ,m_bLevenshtein(sal_False) + ,m_bTransliteration(sal_False) + ,m_bLevRelaxed(sal_False) + ,m_nLevOther(0) + ,m_nLevShorter(0) + ,m_nLevLonger(0) + ,m_nPosition(MATCHING_ANYWHERE) + ,m_nTransliterationFlags(0) +{ + DBG_CTOR(FmSearchEngine,NULL); + + fillControlTexts(arrFields); + Init(sVisibleFields); +} + +//------------------------------------------------------------------------ +FmSearchEngine::~FmSearchEngine() +{ + clearControlTexts(); + + DBG_DTOR(FmSearchEngine,NULL); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SetIgnoreWidthCJK(sal_Bool bSet) +{ + if (bSet) + m_nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH; + else + m_nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::GetIgnoreWidthCJK() const +{ + return 0 != (m_nTransliterationFlags & TransliterationModules_IGNORE_WIDTH); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SetCaseSensitive(sal_Bool bSet) +{ + if (bSet) + m_nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE; + else + m_nTransliterationFlags |= TransliterationModules_IGNORE_CASE; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::GetCaseSensitive() const +{ + return 0 == (m_nTransliterationFlags & TransliterationModules_IGNORE_CASE); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::clearControlTexts() +{ + for ( ControlTextSuppliersIterator aIter = m_aControlTexts.begin(); + aIter < m_aControlTexts.end(); + ++aIter + ) + { + delete *aIter; + } + m_aControlTexts.clear(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields) +{ + clearControlTexts(); + Reference< XInterface > xCurrent; + for (sal_uInt32 i=0; i<arrFields.size(); ++i) + { + xCurrent = arrFields.at(i); + DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !"); + // check which type of control this is + Reference< ::com::sun::star::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY); + if (xAsText.is()) + { + m_aControlTexts.insert(m_aControlTexts.end(), new SimpleTextWrapper(xAsText)); + continue; + } + + Reference< ::com::sun::star::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY); + if (xAsListBox.is()) + { + m_aControlTexts.insert(m_aControlTexts.end(), new ListBoxWrapper(xAsListBox)); + continue; + } + + Reference< ::com::sun::star::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY); + DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !"); + // we don't have any more options ... + m_aControlTexts.insert(m_aControlTexts.end(), new CheckBoxWrapper(xAsCheckBox)); + } +} + +//------------------------------------------------------------------------ +void FmSearchEngine::Init(const ::rtl::OUString& sVisibleFields) +{ + // analyze the fields + // additionally, create the mapping: because the list of used columns can be shorter than the list + // of columns of the cursor, we need a mapping: "used column numer n" -> "cursor column m" + m_arrFieldMapping.clear(); + + // important: The case of the columns does not need to be exact - for instance: + // - a user created a form which works on a table, for which the driver returns a column name "COLUMN" + // - the driver itself works case-insensitve with column names + // - a control in the form is bound to "column" - not the different case + // In such a scenario, the form and the field would work okay, but we here need to case for the different case + // explicitly + // 2003-01-09 - #i8755# - fs@openoffice.org + + // so first of all, check if the database handles identifiers case sensitive + Reference< XConnection > xConn; + Reference< XDatabaseMetaData > xMeta; + Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY ); + if ( xCursorProps.is() ) + { + try + { + xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn; + } + catch( Exception& ) { /* silent this - will be asserted below */ } + } + if ( xConn.is() ) + xMeta = xConn->getMetaData(); + OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" ); + + sal_Bool bCaseSensitiveIdentifiers = sal_True; // assume case sensivity + if ( xMeta.is() ) + bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers(); + + // now that we have this information, we need a collator which is able to case (in)sentively compare strings + m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLocaleData().getLocale(), + bCaseSensitiveIdentifiers ? 0 : ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE ); + + try + { + // der Cursor kann mir einen Record (als PropertySet) liefern, dieser unterstuetzt den DatabaseRecord-Service + Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !"); + Reference< ::com::sun::star::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns(); + Sequence< ::rtl::OUString > seqFieldNames = xAllFieldNames->getElementNames(); + ::rtl::OUString* pFieldNames = seqFieldNames.getArray(); + + + ::rtl::OUString sCurrentField; + UniString sVis(sVisibleFields.getStr()); + xub_StrLen nLen = sVis.GetTokenCount(); + for (xub_StrLen i=0; i<nLen; ++i) + { + sCurrentField = sVis.GetToken(i); + + // in der Feld-Sammlung suchen + sal_Int32 nFoundIndex = -1; + for (sal_Int32 j=0; j<seqFieldNames.getLength(); ++j, ++pFieldNames) + { + if ( 0 == m_aStringCompare.compareString( *pFieldNames, sCurrentField ) ) + { + nFoundIndex = j; + break; + } + } + // set the field selection back to the first + pFieldNames = seqFieldNames.getArray();; + DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Invalid field name were given !"); + m_arrFieldMapping.push_back(nFoundIndex); + } + } + catch(Exception&) + { + DBG_ERROR("Exception occured!"); + } + +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SetFormatterUsing(sal_Bool bSet) +{ + if (m_bFormatter == bSet) + return; + m_bFormatter = bSet; + + if (m_bUsingTextComponents) + { + // ich benutzte keinen Formatter, sondern TextComponents -> der SearchIterator muss angepasst werden + try + { + if (m_bFormatter) + { + DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !"); + m_xSearchCursor = m_xOriginalIterator; + m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark()); + // damit ich mit dem neuen Iterator wirklich dort weitermache, wo ich vorher aufgehoert habe + } + else + { + DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !"); + m_xSearchCursor = m_xClonedIterator; + m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // ich muss die Fields neu binden, da der Textaustausch eventuell ueber diese Fields erfolgt und sich der unterliegende Cursor + // geaendert hat + RebuildUsedFields(m_nCurrentFieldIndex, sal_True); + } + else + InvalidatePreviousLoc(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::PropagateProgress(sal_Bool _bDontPropagateOverflow) +{ + if (m_aProgressHandler.IsSet()) + { + FmSearchProgress aProgress; + try + { + aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS; + aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1; + if (m_bForward) + aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst(); + else + aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + m_aProgressHandler.Call(&aProgress); + } +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SearchNextImpl() +{ + DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard), + "FmSearchEngine::SearchNextImpl : Suchparameter schliessen sich gegenseitig aus !"); + + DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : habe ungueltigen Iterator !"); + + // die Parameter der Suche + ::rtl::OUString strSearchExpression(m_strSearchExpression); // brauche ich non-const + if (!GetCaseSensitive()) + // norm the string + m_aCharacterClassficator.toLower_rtl(strSearchExpression); + + if (!m_bRegular && !m_bLevenshtein) + { // 'normale' Suche fuehre ich auf jeden Fall ueber WildCards durch, muss aber vorher je nach Modus den ::rtl::OUString anpassen + + if (!m_bWildcard) + { // da natuerlich in allen anderen Faellen auch * und ? im Suchstring erlaubt sind, aber nicht als WildCards zaehlen + // sollen, muss ich normieren + UniString aTmp(strSearchExpression.getStr()); + static const UniString s_sStar = UniString::CreateFromAscii("\\*"); + static const UniString s_sQuotation = UniString::CreateFromAscii("\\?"); + aTmp.SearchAndReplaceAll('*', s_sStar); + aTmp.SearchAndReplaceAll('?', s_sQuotation); + strSearchExpression = aTmp; + + switch (m_nPosition) + { + case MATCHING_ANYWHERE : + strSearchExpression = ::rtl::OUString::createFromAscii("*") + strSearchExpression + + ::rtl::OUString::createFromAscii("*"); + break; + case MATCHING_BEGINNING : + strSearchExpression = strSearchExpression + ::rtl::OUString::createFromAscii("*"); + break; + case MATCHING_END : + strSearchExpression = ::rtl::OUString::createFromAscii("*") + strSearchExpression; + break; + case MATCHING_WHOLETEXT : + break; + default : + DBG_ERROR("FmSearchEngine::SearchNextImpl() : die Methoden-Listbox duerfte nur 4 Eintraege enthalten ..."); + } + } + } + + // fuer Arbeit auf Feldliste + FieldCollectionIterator iterBegin = m_arrUsedFields.begin(); + FieldCollectionIterator iterEnd = m_arrUsedFields.end(); + FieldCollectionIterator iterFieldCheck; + + sal_Int32 nFieldPos; + + if (HasPreviousLoc()) + { + DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()), + "FmSearchEngine::SearchNextImpl : ungueltige Position !"); + iterFieldCheck = m_iterPreviousLocField; + // im Feld nach (oder vor) der letzten Fundstelle weitermachen + nFieldPos = iterFieldCheck - iterBegin; + MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd); + } + else + { + if (m_bForward) + iterFieldCheck = iterBegin; + else + { + iterFieldCheck = iterEnd; + --iterFieldCheck; + } + nFieldPos = iterFieldCheck - iterBegin; + } + + PropagateProgress(sal_True); + SEARCH_RESULT srResult; + if (m_eSearchForType != SEARCHFOR_STRING) + srResult = SearchSpecial(m_eSearchForType == SEARCHFOR_NULL, nFieldPos, iterFieldCheck, iterBegin, iterEnd); + else if (!m_bRegular && !m_bLevenshtein) + srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd); + else + srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd); + + m_srResult = srResult; + + if (SR_ERROR == m_srResult) + return; + + // gefunden ? + if (SR_FOUND == m_srResult) + { + // die Pos merken + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldCheck; + } + else + // die "letzte Fundstelle" invalidieren + InvalidatePreviousLoc(); +} + +//------------------------------------------------------------------------ +IMPL_LINK(FmSearchEngine, OnSearchTerminated, FmSearchThread*, /*pThread*/) +{ + if (!m_aProgressHandler.IsSet()) + return 0L; + + FmSearchProgress aProgress; + try + { + switch (m_srResult) + { + case SR_ERROR : + aProgress.aSearchState = FmSearchProgress::STATE_ERROR; + break; + case SR_FOUND : + aProgress.aSearchState = FmSearchProgress::STATE_SUCCESSFULL; + aProgress.aBookmark = m_aPreviousLocBookmark; + aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin(); + break; + case SR_NOTFOUND : + aProgress.aSearchState = FmSearchProgress::STATE_NOTHINGFOUND; + aProgress.aBookmark = m_xSearchCursor.getBookmark(); + break; + case SR_CANCELED : + aProgress.aSearchState = FmSearchProgress::STATE_CANCELED; + aProgress.aBookmark = m_xSearchCursor.getBookmark(); + break; + } + aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // per definitionem muss der Link Thread-sicher sein (das verlange ich einfach), so dass ich mich um so etwas hier nicht kuemmern muss + m_aProgressHandler.Call(&aProgress); + + m_bSearchingCurrently = sal_False; + return 0L; +} + +//------------------------------------------------------------------------ +IMPL_LINK(FmSearchEngine, OnNewRecordCount, void*, pCounterAsVoid) +{ + if (!m_aProgressHandler.IsSet()) + return 0L; + + FmSearchProgress aProgress; + aProgress.nCurrentRecord = (sal_uIntPtr)pCounterAsVoid; + aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS_COUNTING; + m_aProgressHandler.Call(&aProgress); + + return 0L; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::CancelRequested() +{ + m_aCancelAsynchAccess.acquire(); + sal_Bool bReturn = m_bCancelAsynchRequest; + m_aCancelAsynchAccess.release(); + return bReturn; +} + +//------------------------------------------------------------------------ +void FmSearchEngine::CancelSearch() +{ + m_aCancelAsynchAccess.acquire(); + m_bCancelAsynchRequest = sal_True; + m_aCancelAsynchAccess.release(); +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::SwitchToContext(const Reference< ::com::sun::star::sdbc::XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, const InterfaceArray& arrFields, + sal_Int32 nFieldIndex) +{ + DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !"); + if (m_bSearchingCurrently) + return sal_False; + + m_xSearchCursor = xCursor; + m_xOriginalIterator = xCursor; + m_xClonedIterator = CursorWrapper(m_xOriginalIterator, sal_True); + m_bUsingTextComponents = sal_True; + + fillControlTexts(arrFields); + + Init(sVisibleFields); + RebuildUsedFields(nFieldIndex, sal_True); + + return sal_True; +} + +//------------------------------------------------------------------------ +void FmSearchEngine::ImplStartNextSearch() +{ + m_bCancelAsynchRequest = sal_False; + m_bSearchingCurrently = sal_True; + + if (m_eMode == SM_USETHREAD)//CHINA001 if (m_eMode == FmSearchDialog::SM_USETHREAD) + { + FmSearchThread* pSearcher = new FmSearchThread(this); + // der loescht sich nach Beendigung selber ... + pSearcher->setTerminationHandler(LINK(this, FmSearchEngine, OnSearchTerminated)); + + pSearcher->createSuspended(); + pSearcher->setPriority(::vos::OThread::TPriority_Lowest); + pSearcher->resume(); + } + else + { + SearchNextImpl(); + LINK(this, FmSearchEngine, OnSearchTerminated).Call(NULL); + } +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SearchNext(const ::rtl::OUString& strExpression) +{ + m_strSearchExpression = strExpression; + m_eSearchForType = SEARCHFOR_STRING; + ImplStartNextSearch(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SearchNextSpecial(sal_Bool _bSearchForNull) +{ + m_eSearchForType = _bSearchForNull ? SEARCHFOR_NULL : SEARCHFOR_NOTNULL; + ImplStartNextSearch(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::StartOver(const ::rtl::OUString& strExpression) +{ + try + { + if (m_bForward) + m_xSearchCursor.first(); + else + m_xSearchCursor.last(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return; + } + + InvalidatePreviousLoc(); + SearchNext(strExpression); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::StartOverSpecial(sal_Bool _bSearchForNull) +{ + try + { + if (m_bForward) + m_xSearchCursor.first(); + else + m_xSearchCursor.last(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return; + } + + InvalidatePreviousLoc(); + SearchNextSpecial(_bSearchForNull); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::InvalidatePreviousLoc() +{ + m_aPreviousLocBookmark.setValue(0,getVoidCppuType()); + m_iterPreviousLocField = m_arrUsedFields.end(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, sal_Bool bForce) +{ + if (!bForce && (nFieldIndex == m_nCurrentFieldIndex)) + return; + // (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) + + DBG_ASSERT((nFieldIndex == -1) || + ((nFieldIndex >= 0) && + (static_cast<size_t>(nFieldIndex) < m_arrFieldMapping.size())), + "FmSearchEngine::RebuildUsedFields : nFieldIndex is invalid!"); + // alle Felder, die ich durchsuchen muss, einsammeln + m_arrUsedFields.clear(); + if (nFieldIndex == -1) + { + Reference< ::com::sun::star::container::XIndexAccess > xFields; + for (size_t i=0; i<m_arrFieldMapping.size(); ++i) + { + Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !"); + xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY); + BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[i]); + } + } + else + { + Reference< ::com::sun::star::container::XIndexAccess > xFields; + Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !"); + xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY); + BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[static_cast< size_t >(nFieldIndex)]); + } + + m_nCurrentFieldIndex = nFieldIndex; + // und natuerlich beginne ich die naechste Suche wieder jungfraeulich + InvalidatePreviousLoc(); +} + |