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