LibreOffice Module svx (master)  1
fmsrcimp.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <rtl/strbuf.hxx>
22 #include <sal/log.hxx>
23 #include <svx/fmtools.hxx>
24 #include <svx/fmsrccfg.hxx>
25 #include <tools/debug.hxx>
26 #include <tools/diagnose_ex.h>
27 #include <tools/wldcrd.hxx>
28 #include <vcl/svapp.hxx>
29 #include <unotools/textsearch.hxx>
30 #include <com/sun/star/awt/XTextComponent.hpp>
31 #include <com/sun/star/awt/XListBox.hpp>
32 #include <com/sun/star/awt/XCheckBox.hpp>
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include <com/sun/star/util/SearchAlgorithms2.hpp>
35 #include <com/sun/star/util/SearchResult.hpp>
36 #include <com/sun/star/util/SearchFlags.hpp>
37 #include <com/sun/star/lang/Locale.hpp>
38 #include <com/sun/star/i18n/CollatorOptions.hpp>
39 
40 #include <com/sun/star/sdb/XColumn.hpp>
41 #include <com/sun/star/sdbc/SQLException.hpp>
42 #include <com/sun/star/sdbc/XConnection.hpp>
43 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
44 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
45 #include <com/sun/star/util/NumberFormatter.hpp>
46 #include <com/sun/star/util/NumberFormat.hpp>
47 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
48 #include <com/sun/star/util/XNumberFormats.hpp>
49 
50 #include <fmprop.hxx>
51 #include <fmservs.hxx>
52 #include <svx/fmsrcimp.hxx>
53 #include <svx/fmsearch.hxx>
54 
55 #include <comphelper/types.hxx>
56 #include <unotools/syslocale.hxx>
57 #include <i18nutil/searchopt.hxx>
58 
59 #define EQUAL_BOOKMARKS(a, b) a == b
60 
61 #define IFACECAST(c) static_cast<const Reference< XInterface >&>(c)
62 
63 using namespace ::com::sun::star::uno;
64 using namespace ::com::sun::star::util;
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::sdbc;
67 using namespace ::com::sun::star::i18n;
68 using namespace ::com::sun::star::beans;
69 using namespace ::svxform;
70 
71 
72 // = FmRecordCountListener
73 
74 // SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject);
75 
76 
77 FmRecordCountListener::FmRecordCountListener(const Reference< css::sdbc::XResultSet > & dbcCursor)
78 {
79 
80  m_xListening.set(dbcCursor, UNO_QUERY);
81  if (!m_xListening.is())
82  return;
83 
84  if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL)))
85  {
86  m_xListening = nullptr;
87  // there's nothing to do as the record count is already known
88  return;
89  }
90 
91  m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, static_cast<css::beans::XPropertyChangeListener*>(this));
92 }
93 
94 
96 {
97  m_lnkWhoWantsToKnow = lnk;
98 
99  if (m_xListening.is())
101 }
102 
103 
105 {
106 
107 }
108 
109 
111 {
112  if(m_xListening.is())
113  m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, static_cast<css::beans::XPropertyChangeListener*>(this));
114  m_xListening = nullptr;
115 }
116 
117 
118 void SAL_CALL FmRecordCountListener::disposing(const css::lang::EventObject& /*Source*/)
119 {
120  DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !");
121  DisConnect();
122 }
123 
124 
126 {
127  if (m_lnkWhoWantsToKnow.IsSet())
128  {
129  DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?");
130  sal_Int32 theCount = ::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT));
131  m_lnkWhoWantsToKnow.Call(theCount);
132  }
133 }
134 
135 
136 void FmRecordCountListener::propertyChange(const css::beans::PropertyChangeEvent& /*evt*/)
137 {
139 }
140 
141 
142 // FmSearchEngine - local classes
143 
144 SimpleTextWrapper::SimpleTextWrapper(const Reference< css::awt::XTextComponent > & _xText)
145  :ControlTextWrapper(_xText.get())
146  ,m_xText(_xText)
147 {
148  DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !");
149 }
150 
151 
153 {
154  return m_xText->getText();
155 }
156 
157 
158 ListBoxWrapper::ListBoxWrapper(const Reference< css::awt::XListBox > & _xBox)
159  :ControlTextWrapper(_xBox.get())
160  ,m_xBox(_xBox)
161 {
162  DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !");
163 }
164 
165 
167 {
168  return m_xBox->getSelectedItem();
169 }
170 
171 
172 CheckBoxWrapper::CheckBoxWrapper(const Reference< css::awt::XCheckBox > & _xBox)
173  :ControlTextWrapper(_xBox.get())
174  ,m_xBox(_xBox)
175 {
176  DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !");
177 }
178 
179 
181 {
182  switch (static_cast<TriState>(m_xBox->getState()))
183  {
184  case TRISTATE_FALSE: return "0";
185  case TRISTATE_TRUE: return "1";
186  default: break;
187  }
188  return OUString();
189 }
190 
191 
192 // = FmSearchEngine
193 
195 {
196  bool bSuccess = true;
197  try
198  {
199  if (m_bForward)
200  if (m_xSearchCursor.isLast())
201  m_xSearchCursor.first();
202  else
203  m_xSearchCursor.next();
204  else
205  if (m_xSearchCursor.isFirst())
206  {
207  rtl::Reference<FmRecordCountListener> prclListener = new FmRecordCountListener(m_xSearchCursor);
208  prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount));
209 
210  m_xSearchCursor.last();
211 
212  prclListener->DisConnect();
213  }
214  else
215  m_xSearchCursor.previous();
216  }
217  catch(Exception const&)
218  {
219  TOOLS_WARN_EXCEPTION( "svx", "FmSearchEngine::MoveCursor");
220  bSuccess = false;
221  }
222  catch(...)
223  {
224  OSL_FAIL("FmSearchEngine::MoveCursor : caught an unknown Exception !");
225  bSuccess = false;
226  }
227 
228  return bSuccess;
229 }
230 
231 
232 bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollection::iterator& iter, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
233 {
234  bool bSuccess(true);
235  if (m_bForward)
236  {
237  ++iter;
238  ++nPos;
239  if (iter == iterEnd)
240  {
241  bSuccess = MoveCursor();
242  iter = iterBegin;
243  nPos = 0;
244  }
245  } else
246  {
247  if (iter == iterBegin)
248  {
249  bSuccess = MoveCursor();
250  iter = iterEnd;
251  nPos = iter-iterBegin;
252  }
253  --iter;
254  --nPos;
255  }
256  return bSuccess;
257 }
258 
259 
260 void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< css::container::XIndexAccess > & xAllFields, sal_Int32 nField)
261 {
262  DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ),
263  "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" );
264 
265  // the field itself
266  Reference< XInterface > xCurrentField;
267  xAllFields->getByIndex(nField) >>= xCurrentField;
268 
269  // From this I now know that it supports the DatabaseRecord service (I hope).
270  // For the FormatKey and the type I need the PropertySet.
271  Reference< css::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY);
272 
273  // build the FieldInfo for that
274  FieldInfo fiCurrent;
275  fiCurrent.xContents.set(xCurrentField, UNO_QUERY);
276 
277  // and memorize
278  m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent);
279 
280 }
281 
282 OUString FmSearchEngine::FormatField(sal_Int32 nWhich)
283 {
284  DBG_ASSERT(static_cast<sal_uInt32>(nWhich) < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !");
285  DBG_ASSERT(m_aControlTexts[nWhich], "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !");
286  DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !");
287 
288  if (m_nCurrentFieldIndex != -1)
289  {
290  DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : parameter nWhich is invalid");
291  // analogous situation as below
292  nWhich = m_nCurrentFieldIndex;
293  }
294 
295  DBG_ASSERT((nWhich >= 0) && (static_cast<sal_uInt32>(nWhich) < m_aControlTexts.size()),
296  "FmSearchEngine::FormatField : invalid argument nWhich !");
297  return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText();
298 }
299 
300 
301 FmSearchEngine::SearchResult FmSearchEngine::SearchSpecial(bool _bSearchForNull, sal_Int32& nFieldPos,
302  FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
303 {
304  // memorize the start position
305  Any aStartMark;
306  try { aStartMark = m_xSearchCursor.getBookmark(); }
307  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
308  FieldCollection::const_iterator iterInitialField = iterFieldLoop;
309 
310 
311  bool bFound(false);
312  bool bMovedAround(false);
313  do
314  {
315  Application::Reschedule( true );
316 
317  // the content to be compared currently
318  iterFieldLoop->xContents->getString(); // needed for wasNull
319  bFound = _bSearchForNull == bool(iterFieldLoop->xContents->wasNull());
320  if (bFound)
321  break;
322 
323  // next field (implicitly next record, if necessary)
324  if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
325  { // When moving to the next field, something went wrong...
326  // Continuing is not possible, since the next time exactly the same
327  // will definitely go wrong again, thus abort.
328  // Before, however, so that the search continues at the current position:
329  try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
330  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
331  m_iterPreviousLocField = iterFieldLoop;
332  // and leave
333  return SearchResult::Error;
334  }
335 
336  Any aCurrentBookmark;
337  try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
338  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
339 
340  bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
341 
342  if (nFieldPos == 0)
343  // that is, I've moved to a new record
344  PropagateProgress(bMovedAround);
345  // if we moved to the starting position we don't have to propagate an 'overflow' message
346  // FS - 07.12.99 - 68530
347 
348  // cancel requested?
349  if (CancelRequested())
350  return SearchResult::Cancelled;
351 
352  } while (!bMovedAround);
353 
354  return bFound ? SearchResult::Found : SearchResult::NotFound;
355 }
356 
357 
358 FmSearchEngine::SearchResult FmSearchEngine::SearchWildcard(const OUString& strExpression, sal_Int32& nFieldPos,
359  FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
360 {
361  // memorize the start position
362  Any aStartMark;
363  try { aStartMark = m_xSearchCursor.getBookmark(); }
364  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
365  FieldCollection::const_iterator iterInitialField = iterFieldLoop;
366 
367  WildCard aSearchExpression(strExpression);
368 
369 
370  bool bFound(false);
371  bool bMovedAround(false);
372  do
373  {
374  Application::Reschedule( true );
375 
376  // the content to be compared currently
377  OUString sCurrentCheck;
378  if (m_bFormatter)
379  sCurrentCheck = FormatField(nFieldPos);
380  else
381  sCurrentCheck = iterFieldLoop->xContents->getString();
382 
383  if (!GetCaseSensitive())
384  // norm the string
385  sCurrentCheck = m_aCharacterClassficator.lowercase(sCurrentCheck);
386 
387  // now the test is easy...
388  bFound = aSearchExpression.Matches(sCurrentCheck);
389 
390  if (bFound)
391  break;
392 
393  // next field (implicitly next record, if necessary)
394  if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
395  { // When moving to the next field, something went wrong...
396  // Continuing is not possible, since the next time exactly the same
397  // will definitely go wrong again, thus abort.
398  // Before, however, so that the search continues at the current position:
399  try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
400  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
401  m_iterPreviousLocField = iterFieldLoop;
402  // and leave
403  return SearchResult::Error;
404  }
405 
406  Any aCurrentBookmark;
407  try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
408  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
409 
410  bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
411 
412  if (nFieldPos == 0)
413  // that is, I've moved to a new record
414  PropagateProgress(bMovedAround);
415  // if we moved to the starting position we don't have to propagate an 'overflow' message
416  // FS - 07.12.99 - 68530
417 
418  // cancel requested?
419  if (CancelRequested())
420  return SearchResult::Cancelled;
421 
422  } while (!bMovedAround);
423 
424  return bFound ? SearchResult::Found : SearchResult::NotFound;
425 }
426 
427 
428 FmSearchEngine::SearchResult FmSearchEngine::SearchRegularApprox(const OUString& strExpression, sal_Int32& nFieldPos,
429  FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
430 {
431  DBG_ASSERT(m_bLevenshtein || m_bRegular,
432  "FmSearchEngine::SearchRegularApprox : invalid search mode!");
433  DBG_ASSERT(!m_bLevenshtein || !m_bRegular,
434  "FmSearchEngine::SearchRegularApprox : cannot search for regular expressions and similarities at the same time!");
435 
436  // memorize start position
437  Any aStartMark;
438  try { aStartMark = m_xSearchCursor.getBookmark(); }
439  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
440  FieldCollection::const_iterator iterInitialField = iterFieldLoop;
441 
442  // collect parameters
444  aParam.AlgorithmType2 = m_bRegular ? SearchAlgorithms2::REGEXP : SearchAlgorithms2::APPROXIMATE;
445  aParam.searchFlag = 0;
446  aParam.transliterateFlags = GetTransliterationFlags();
447  if ( !GetTransliteration() )
448  { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH
449  aParam.transliterateFlags &= TransliterationFlags::IGNORE_CASE | TransliterationFlags::IGNORE_WIDTH;
450  }
451  if (m_bLevenshtein)
452  {
453  if (m_bLevRelaxed)
454  aParam.searchFlag |= SearchFlags::LEV_RELAXED;
455  aParam.changedChars = m_nLevOther;
456  aParam.deletedChars = m_nLevShorter;
457  aParam.insertedChars = m_nLevLonger;
458  }
459  aParam.searchString = strExpression;
461  ::utl::TextSearch aLocalEngine( aParam);
462 
463 
464  bool bFound = false;
465  bool bMovedAround(false);
466  do
467  {
468  Application::Reschedule( true );
469 
470  // the content to be compared currently
471  OUString sCurrentCheck;
472  if (m_bFormatter)
473  sCurrentCheck = FormatField(nFieldPos);
474  else
475  sCurrentCheck = iterFieldLoop->xContents->getString();
476 
477  // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it)
478 
479  sal_Int32 nStart = 0, nEnd = sCurrentCheck.getLength();
480  bFound = aLocalEngine.SearchForward(sCurrentCheck, &nStart, &nEnd);
481  // it says 'forward' here, but that only refers to the search within
482  // sCurrentCheck, so it has nothing to do with the direction of my
483  // record migration (MoveField takes care of that)
484 
485  // check if the position is correct
486  if (bFound)
487  {
488  switch (m_nPosition)
489  {
490  case MATCHING_WHOLETEXT :
491  if (nEnd != sCurrentCheck.getLength())
492  {
493  bFound = false;
494  break;
495  }
496  [[fallthrough]];
497  case MATCHING_BEGINNING :
498  if (nStart != 0)
499  bFound = false;
500  break;
501  case MATCHING_END :
502  if (nEnd != sCurrentCheck.getLength())
503  bFound = false;
504  break;
505  }
506  }
507 
508  if (bFound) // still?
509  break;
510 
511  // next field (implicitly next record, if necessary)
512  if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
513  { // When moving to the next field, something went wrong...
514  // Continuing is not possible, since the next time exactly the same
515  // will definitely go wrong again, thus abort (without error
516  // notification, I expect it to be displayed in the Move).
517  // Before, however, so that the search continues at the current position:
518  try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
519  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
520  m_iterPreviousLocField = iterFieldLoop;
521  // and leave
522  return SearchResult::Error;
523  }
524 
525  Any aCurrentBookmark;
526  try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
527  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
528  bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
529 
530  if (nFieldPos == 0)
531  // that is, I've moved to a new record
532  PropagateProgress(bMovedAround);
533  // if we moved to the starting position we don't have to propagate an 'overflow' message
534  // FS - 07.12.99 - 68530
535 
536  // cancel requested?
537  if (CancelRequested())
538  return SearchResult::Cancelled;
539 
540  } while (!bMovedAround);
541 
542  return bFound ? SearchResult::Found : SearchResult::NotFound;
543 }
544 
545 
547  const Reference< XResultSet > & xCursor, const OUString& sVisibleFields,
548  const InterfaceArray& arrFields)
549  :m_xSearchCursor(xCursor)
550  ,m_aCharacterClassficator( _rxContext, SvtSysLocale().GetLanguageTag() )
551  ,m_aStringCompare( _rxContext )
552  ,m_nCurrentFieldIndex(-2) // -1 already has a meaning, so I take -2 for 'invalid'
553  ,m_xOriginalIterator(xCursor)
554  ,m_xClonedIterator(m_xOriginalIterator, true)
555  ,m_eSearchForType(SearchFor::String)
556  ,m_srResult(SearchResult::Found)
557  ,m_bSearchingCurrently(false)
558  ,m_bCancelAsynchRequest(false)
559  ,m_bFormatter(true) // this must be consistent with m_xSearchCursor, which is generally == m_xOriginalIterator
560  ,m_bForward(false)
561  ,m_bWildcard(false)
562  ,m_bRegular(false)
563  ,m_bLevenshtein(false)
564  ,m_bTransliteration(false)
565  ,m_bLevRelaxed(false)
566  ,m_nLevOther(0)
567  ,m_nLevShorter(0)
568  ,m_nLevLonger(0)
570  ,m_nTransliterationFlags(TransliterationFlags::NONE)
571 {
572 
573  fillControlTexts(arrFields);
574  Init(sVisibleFields);
575 }
576 
577 
579 {
580  if (bSet)
581  m_nTransliterationFlags |= TransliterationFlags::IGNORE_WIDTH;
582  else
584 }
585 
586 
588 {
589  return bool(m_nTransliterationFlags & TransliterationFlags::IGNORE_WIDTH);
590 }
591 
592 
594 {
595  if (bSet)
597  else
598  m_nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
599 }
600 
601 
603 {
604  return !(m_nTransliterationFlags & TransliterationFlags::IGNORE_CASE);
605 }
606 
607 
609 {
610  m_aControlTexts.clear();
611  Reference< XInterface > xCurrent;
612  for (const auto & rField : arrFields)
613  {
614  xCurrent = rField;
615  DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !");
616  // check which type of control this is
617  Reference< css::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY);
618  if (xAsText.is())
619  {
620  m_aControlTexts.emplace_back(new SimpleTextWrapper(xAsText));
621  continue;
622  }
623 
624  Reference< css::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY);
625  if (xAsListBox.is())
626  {
627  m_aControlTexts.emplace_back(new ListBoxWrapper(xAsListBox));
628  continue;
629  }
630 
631  Reference< css::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY);
632  DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !");
633  // we don't have any more options ...
634  m_aControlTexts.emplace_back(new CheckBoxWrapper(xAsCheckBox));
635  }
636 }
637 
638 
639 void FmSearchEngine::Init(const OUString& sVisibleFields)
640 {
641  // analyze the fields
642  // additionally, create the mapping: because the list of used columns can be shorter than the list
643  // of columns of the cursor, we need a mapping: "used column number n" -> "cursor column m"
644  m_arrFieldMapping.clear();
645 
646  // important: The case of the columns does not need to be exact - for instance:
647  // - a user created a form which works on a table, for which the driver returns a column name "COLUMN"
648  // - the driver itself works case-insensitive with column names
649  // - a control in the form is bound to "column" - not the different case
650  // In such a scenario, the form and the field would work okay, but we here need to case for the different case
651  // explicitly
652  // #i8755#
653 
654  // so first of all, check if the database handles identifiers case sensitive
655  Reference< XConnection > xConn;
656  Reference< XDatabaseMetaData > xMeta;
657  Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY );
658  if ( xCursorProps.is() )
659  {
660  try
661  {
662  xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn;
663  }
664  catch( const Exception& ) { /* silent this - will be asserted below */ }
665  }
666  if ( xConn.is() )
667  xMeta = xConn->getMetaData();
668  OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" );
669 
670  bool bCaseSensitiveIdentifiers = true; // assume case sensitivity
671  if ( xMeta.is() )
672  bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers();
673 
674  // now that we have this information, we need a collator which is able to case (in)sensitivity compare strings
675  m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLanguageTag().getLocale(),
676  bCaseSensitiveIdentifiers ? 0 : css::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
677 
678  try
679  {
680  // the cursor can give me a record (as PropertySet), which supports the DatabaseRecord service
681  Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
682  DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !");
683  Reference< css::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns();
684  Sequence< OUString > seqFieldNames = xAllFieldNames->getElementNames();
685 
686  OUString sCurrentField;
687  sal_Int32 nIndex = 0;
688  do
689  {
690  sCurrentField = sVisibleFields.getToken(0, ';' , nIndex);
691 
692  // search in the field collection
693  sal_Int32 nFoundIndex = -1;
694  auto pFieldName = std::find_if(seqFieldNames.begin(), seqFieldNames.end(),
695  [this, &sCurrentField](const OUString& rFieldName) {
696  return 0 == m_aStringCompare.compareString( rFieldName, sCurrentField ); });
697  if (pFieldName != seqFieldNames.end())
698  nFoundIndex = static_cast<sal_Int32>(std::distance(seqFieldNames.begin(), pFieldName));
699  DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Invalid field name were given !");
700  m_arrFieldMapping.push_back(nFoundIndex);
701  }
702  while ( nIndex >= 0 );
703  }
704  catch (const Exception&)
705  {
706  OSL_FAIL("Exception occurred!");
707  }
708 
709 }
710 
711 
713 {
714  if (m_bFormatter == bSet)
715  return;
716  m_bFormatter = bSet;
717 
718  // I did not use a formatter, but TextComponents -> the SearchIterator needs to be adjusted
719  try
720  {
721  if (m_bFormatter)
722  {
723  DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inconsistent state !");
726  // so that I continue with the new iterator at the actual place where I previously stopped
727  }
728  else
729  {
730  DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inconsistent state !");
733  }
734  }
735  catch( const Exception& )
736  {
738  }
739 
740  // I have to re-bind the fields, because the text exchange might take
741  // place over these fields and the underlying cursor has changed
743 }
744 
745 
746 void FmSearchEngine::PropagateProgress(bool _bDontPropagateOverflow)
747 {
749  {
750  FmSearchProgress aProgress;
751  try
752  {
754  aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
755  if (m_bForward)
756  aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst();
757  else
758  aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast();
759  }
760  catch( const Exception& )
761  {
763  }
764 
765  m_aProgressHandler.Call(&aProgress);
766  }
767 }
768 
769 
771 {
773  "FmSearchEngine::SearchNextImpl : search parameters are mutually exclusive!");
774 
775  DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : have invalid iterator!");
776 
777  // the parameters of the search
778  OUString strSearchExpression(m_strSearchExpression); // I need non-const
779  if (!GetCaseSensitive())
780  // norm the string
781  strSearchExpression = m_aCharacterClassficator.lowercase(strSearchExpression);
782 
783  if (!m_bRegular && !m_bLevenshtein)
784  { // 'normal' search I run through WildCards in any case, but must before adjust the OUString depending on the mode
785 
786  if (!m_bWildcard)
787  { // since in all other cases * and ? in the search string are of course
788  // also allowed, but should not count as WildCards, I need to normalize
789  OUString aTmp(strSearchExpression);
790  const OUString s_sStar("\\*");
791  const OUString s_sQuotation("\\?");
792  aTmp = aTmp.replaceAll("*", s_sStar);
793  aTmp = aTmp.replaceAll("?", s_sQuotation);
794  strSearchExpression = aTmp;
795 
796  switch (m_nPosition)
797  {
798  case MATCHING_ANYWHERE :
799  strSearchExpression = "*" + strSearchExpression + "*";
800  break;
801  case MATCHING_BEGINNING :
802  strSearchExpression += "*";
803  break;
804  case MATCHING_END :
805  strSearchExpression = "*" + strSearchExpression;
806  break;
807  case MATCHING_WHOLETEXT :
808  break;
809  default :
810  OSL_FAIL("FmSearchEngine::SearchNextImpl() : the methods listbox may contain only 4 entries ...");
811  }
812  }
813  }
814 
815  // for work on field list
816  FieldCollection::iterator iterBegin = m_arrUsedFields.begin();
817  FieldCollection::iterator iterEnd = m_arrUsedFields.end();
818  FieldCollection::iterator iterFieldCheck;
819 
820  sal_Int32 nFieldPos;
821 
822  if (m_aPreviousLocBookmark.hasValue())
823  {
825  "FmSearchEngine::SearchNextImpl : invalid position!");
826  iterFieldCheck = m_iterPreviousLocField;
827  // continue in the field after (or before) the last discovery
828  nFieldPos = iterFieldCheck - iterBegin;
829  MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd);
830  }
831  else
832  {
833  if (m_bForward)
834  iterFieldCheck = iterBegin;
835  else
836  {
837  iterFieldCheck = iterEnd;
838  --iterFieldCheck;
839  }
840  nFieldPos = iterFieldCheck - iterBegin;
841  }
842 
843  PropagateProgress(true);
844  SearchResult srResult;
846  srResult = SearchSpecial(m_eSearchForType == SearchFor::Null, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
847  else if (!m_bRegular && !m_bLevenshtein)
848  srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
849  else
850  srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
851 
852  m_srResult = srResult;
853 
855  return;
856 
857  // found?
859  {
860  // memorize the position
862  catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
863  m_iterPreviousLocField = iterFieldCheck;
864  }
865  else
866  // invalidate the "last discovery"
868 }
869 
870 
872 {
873  if (!m_aProgressHandler.IsSet())
874  return;
875 
876  FmSearchProgress aProgress;
877  try
878  {
879  switch (m_srResult)
880  {
881  case SearchResult::Error :
883  break;
884  case SearchResult::Found :
886  aProgress.aBookmark = m_aPreviousLocBookmark;
887  aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin();
888  break;
891  aProgress.aBookmark = m_xSearchCursor.getBookmark();
892  break;
895  aProgress.aBookmark = m_xSearchCursor.getBookmark();
896  break;
897  }
898  aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
899  }
900  catch( const Exception& )
901  {
903  }
904 
905  // by definition, the link must be thread-safe (I just require that),
906  // so that I do not have to worry about such things here
907  m_aProgressHandler.Call(&aProgress);
908 
909  m_bSearchingCurrently = false;
910 }
911 
912 
913 IMPL_LINK(FmSearchEngine, OnNewRecordCount, sal_Int32, theCounter, void)
914 {
915  if (!m_aProgressHandler.IsSet())
916  return;
917 
918  FmSearchProgress aProgress;
919  aProgress.nCurrentRecord = theCounter;
921  m_aProgressHandler.Call(&aProgress);
922 }
923 
924 
926 {
927  m_aCancelAsynchAccess.acquire();
928  bool bReturn = m_bCancelAsynchRequest;
929  m_aCancelAsynchAccess.release();
930  return bReturn;
931 }
932 
933 
935 {
936  m_aCancelAsynchAccess.acquire();
937  m_bCancelAsynchRequest = true;
938  m_aCancelAsynchAccess.release();
939 }
940 
941 
942 void FmSearchEngine::SwitchToContext(const Reference< css::sdbc::XResultSet > & xCursor, const OUString& sVisibleFields, const InterfaceArray& arrFields,
943  sal_Int32 nFieldIndex)
944 {
945  DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !");
947  return;
948 
949  m_xSearchCursor = xCursor;
950  m_xOriginalIterator = xCursor;
952 
953  fillControlTexts(arrFields);
954 
955  Init(sVisibleFields);
956  RebuildUsedFields(nFieldIndex, true);
957 }
958 
959 
961 {
962  m_bCancelAsynchRequest = false;
963  m_bSearchingCurrently = true;
964 
965  SearchNextImpl();
967 }
968 
969 
970 void FmSearchEngine::SearchNext(const OUString& strExpression)
971 {
972  m_strSearchExpression = strExpression;
975 }
976 
977 
978 void FmSearchEngine::SearchNextSpecial(bool _bSearchForNull)
979 {
982 }
983 
984 
985 void FmSearchEngine::StartOver(const OUString& strExpression)
986 {
987  try
988  {
989  if (m_bForward)
991  else
993  }
994  catch( const Exception& )
995  {
997  return;
998  }
999 
1001  SearchNext(strExpression);
1002 }
1003 
1004 
1005 void FmSearchEngine::StartOverSpecial(bool _bSearchForNull)
1006 {
1007  try
1008  {
1009  if (m_bForward)
1011  else
1013  }
1014  catch( const Exception& )
1015  {
1016  DBG_UNHANDLED_EXCEPTION("svx");
1017  return;
1018  }
1019 
1021  SearchNextSpecial(_bSearchForNull);
1022 }
1023 
1024 
1026 {
1027  m_aPreviousLocBookmark.clear();
1029 }
1030 
1031 
1032 void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, bool bForce)
1033 {
1034  if (!bForce && (nFieldIndex == m_nCurrentFieldIndex))
1035  return;
1036  // (since I allow no change of the iterator from the outside, the same css::sdbcx::Index
1037  // also always means the same column, so I have nothing to do)
1038 
1039  DBG_ASSERT((nFieldIndex == -1) ||
1040  ((nFieldIndex >= 0) &&
1041  (static_cast<size_t>(nFieldIndex) < m_arrFieldMapping.size())),
1042  "FmSearchEngine::RebuildUsedFields : nFieldIndex is invalid!");
1043  // collect all fields I need to search through
1044  m_arrUsedFields.clear();
1045  if (nFieldIndex == -1)
1046  {
1047  Reference< css::container::XIndexAccess > xFields;
1048  for (sal_Int32 i : m_arrFieldMapping)
1049  {
1050  Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1051  DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1052  xFields.set(xSupplyCols->getColumns(), UNO_QUERY);
1053  BuildAndInsertFieldInfo(xFields, i);
1054  }
1055  }
1056  else
1057  {
1058  Reference< css::container::XIndexAccess > xFields;
1059  Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
1060  DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
1061  xFields.set (xSupplyCols->getColumns(), UNO_QUERY);
1062  BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[static_cast< size_t >(nFieldIndex)]);
1063  }
1064 
1065  m_nCurrentFieldIndex = nFieldIndex;
1066  // and of course I start the next search in a virgin state again
1068 }
1069 
1070 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
#define MATCHING_END
Definition: fmsrccfg.hxx:31
sal_Int32 nIndex
TransliterationFlags m_nTransliterationFlags
Definition: fmsrcimp.hxx:213
ListBoxWrapper(const css::uno::Reference< css::awt::XListBox > &_xBox)
Definition: fmsrcimp.cxx:158
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
sal_Int32 nFieldIndex
Definition: fmsrcimp.hxx:64
Link< const FmSearchProgress *, void > m_aProgressHandler
Definition: fmsrcimp.hxx:192
sal_Int32 getRow() const
Definition: fmtools.hxx:114
SVX_DLLPRIVATE bool MoveField(sal_Int32 &nPos, FieldCollection::iterator &iter, const FieldCollection::iterator &iterBegin, const FieldCollection::iterator &iterEnd)
Definition: fmsrcimp.cxx:232
void InvalidatePreviousLoc()
invalidate previous search reference
Definition: fmsrcimp.cxx:1025
FieldCollection::iterator m_iterPreviousLocField
Definition: fmsrcimp.hxx:184
css::uno::Any aBookmark
Definition: fmsrcimp.hxx:62
virtual OUString getCurrentText() const override
Definition: fmsrcimp.cxx:180
void Init(const OUString &strVisibleFields)
Definition: fmsrcimp.cxx:639
bool getBOOL(const Any &_rAny)
#define FM_PROP_ROWCOUNTFINAL
Definition: fmprop.hxx:33
SVX_DLLPRIVATE SearchResult SearchRegularApprox(const OUString &strExpression, sal_Int32 &nFieldPos, FieldCollection::iterator &iterFieldLoop, const FieldCollection::iterator &iterBegin, const FieldCollection::iterator &iterEnd)
Definition: fmsrcimp.cxx:428
bool m_bSearchingCurrently
Definition: fmsrcimp.hxx:193
void StartOver(const OUString &strExpression)
search for the next appearance, dependent on nDirection from the start or end
Definition: fmsrcimp.cxx:985
void SwitchToContext(const css::uno::Reference< css::sdbc::XResultSet > &xCursor, const OUString &strVisibleFields, const InterfaceArray &arrFields, sal_Int32 nFieldIndex)
only valid, if not an (asynchronous) search is running, the next search will then be executed on top ...
Definition: fmsrcimp.cxx:942
CursorWrapper m_xOriginalIterator
Definition: fmsrcimp.hxx:179
bool isFirst() const
Definition: fmtools.hxx:109
bool isLast() const
Definition: fmtools.hxx:110
class FmRecordCountListener - utility class for FmSearchEngine, listens at a certain cursor and provi...
Definition: fmsrcimp.hxx:71
TRISTATE_TRUE
css::uno::Any m_aPreviousLocBookmark
Definition: fmsrcimp.hxx:183
SVX_DLLPRIVATE bool MoveCursor()
Definition: fmsrcimp.cxx:194
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
NONE
void SearchNextSpecial(bool _bSearchForNull)
analogous, search for "NULL" (_bSearchForNull==sal_True) or "not NULL"
Definition: fmsrcimp.cxx:978
std::vector< css::uno::Reference< css::uno::XInterface > > InterfaceArray
Definition: fmsrcimp.hxx:149
CollatorWrapper m_aStringCompare
Definition: fmsrcimp.hxx:164
sal_uInt32 nCurrentRecord
Definition: fmsrcimp.hxx:57
State aSearchState
Definition: fmsrcimp.hxx:54
FieldCollection m_arrUsedFields
Definition: fmsrcimp.hxx:173
css::uno::Reference< css::awt::XCheckBox > m_xBox
Definition: fmsrcimp.hxx:142
OUString FormatField(sal_Int32 nWhich)
Definition: fmsrcimp.cxx:282
void SetCaseSensitive(bool bSet)
Definition: fmsrcimp.cxx:593
virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent &evt) override
Definition: fmsrcimp.cxx:136
SVX_DLLPRIVATE SearchResult SearchWildcard(const OUString &strExpression, sal_Int32 &nFieldPos, FieldCollection::iterator &iterFieldLoop, const FieldCollection::iterator &iterBegin, const FieldCollection::iterator &iterEnd)
Definition: fmsrcimp.cxx:358
#define EQUAL_BOOKMARKS(a, b)
Definition: fmsrcimp.cxx:59
IMPL_LINK(FmSearchEngine, OnNewRecordCount, sal_Int32, theCounter, void)
Definition: fmsrcimp.cxx:913
void CancelSearch()
returns directly; once it was really aborted, ProgressHandler is called with STATE_CANCELED ...
Definition: fmsrcimp.cxx:934
void SetFormatterUsing(bool bSet)
Definition: fmsrcimp.cxx:712
TransliterationFlags
bool moveToBookmark(const css::uno::Any &bookmark)
Definition: fmtools.hxx:104
css::uno::Reference< css::beans::XPropertySet > m_xListening
Definition: fmsrcimp.hxx:75
css::lang::Locale Locale
bool m_bCancelAsynchRequest
Definition: fmsrcimp.hxx:194
bool SearchForward(const OUString &rStr, sal_Int32 *pStart, sal_Int32 *pEnd, css::util::SearchResult *pRes=nullptr)
bool Matches(const OUString &rStr) const
#define DBG_UNHANDLED_EXCEPTION(...)
#define TOOLS_WARN_EXCEPTION(area, stream)
css::uno::Reference< css::awt::XListBox > m_xBox
Definition: fmsrcimp.hxx:134
static bool Reschedule(bool bHandleAllCurrentEvents=false)
#define DBG_ASSERT(sCon, aError)
std::deque< sal_Int32 > m_arrFieldMapping
Definition: fmsrcimp.hxx:159
bool last()
Definition: fmtools.hxx:113
SVX_DLLPRIVATE void PropagateProgress(bool _bDontPropagateOverflow)
Definition: fmsrcimp.cxx:746
TransliterationFlags transliterateFlags
SVX_DLLPRIVATE SearchResult SearchSpecial(bool _bSearchForNull, sal_Int32 &nFieldPos, FieldCollection::iterator &iterFieldLoop, const FieldCollection::iterator &iterBegin, const FieldCollection::iterator &iterEnd)
Definition: fmsrcimp.cxx:301
int i
TRISTATE_FALSE
sal_Int32 loadDefaultCollator(const css::lang::Locale &rLocale, sal_Int32 nOption)
std::vector< std::unique_ptr< svxform::ControlTextWrapper > > m_aControlTexts
Definition: fmsrcimp.hxx:177
SVX_DLLPRIVATE void fillControlTexts(const InterfaceArray &arrFields)
Definition: fmsrcimp.cxx:608
#define FM_PROP_ROWCOUNT
Definition: fmprop.hxx:32
void RebuildUsedFields(sal_Int32 nFieldIndex, bool bForce=false)
rebuilds m_arrUsedFields (nFieldIndex==-1 means all fields, otherwise it specifies the field index) i...
Definition: fmsrcimp.cxx:1032
struct FmSearchProgress - the owner of SearchEngine receives this structure for status updates (at th...
Definition: fmsrcimp.hxx:49
OUString lowercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
bool GetCaseSensitive() const
Definition: fmsrcimp.cxx:602
sal_Int32 m_nCurrentFieldIndex
Definition: fmsrcimp.hxx:174
#define MATCHING_ANYWHERE
Definition: fmsrccfg.hxx:29
void OnSearchTerminated()
Definition: fmsrcimp.cxx:871
SearchFor m_eSearchForType
Definition: fmsrcimp.hxx:188
bool m_bLevenshtein
Definition: fmsrcimp.hxx:203
OUString m_strSearchExpression
Definition: fmsrcimp.hxx:187
void SearchNext(const OUString &strExpression)
search for the next appearance (for nDirection values check DIRECTION_*-defines)
Definition: fmsrcimp.cxx:970
virtual ~FmRecordCountListener() override
Definition: fmsrcimp.cxx:104
bool GetIgnoreWidthCJK() const
Definition: fmsrcimp.cxx:587
sal_uInt16 m_nPosition
Definition: fmsrcimp.hxx:211
void SearchNextImpl()
Definition: fmsrcimp.cxx:770
void ImplStartNextSearch()
Definition: fmsrcimp.cxx:960
::osl::Mutex m_aCancelAsynchAccess
Definition: fmsrcimp.hxx:195
sal_Int32 m_nPosition
FmSearchEngine(const css::uno::Reference< css::uno::XComponentContext > &_rxContext, const css::uno::Reference< css::sdbc::XResultSet > &xCursor, const OUString &strVisibleFields, const InterfaceArray &arrFields)
two constructs, both analogical to FmSearchDialog, therefore look this up for explanations...
Definition: fmsrcimp.cxx:546
CursorWrapper m_xSearchCursor
Definition: fmsrcimp.hxx:158
#define FM_PROP_ACTIVE_CONNECTION
Definition: fmprop.hxx:128
css::uno::Reference< css::sdb::XColumn > xContents
Definition: fmsrcimp.hxx:169
#define MATCHING_BEGINNING
Definition: fmsrccfg.hxx:30
#define IFACECAST(c)
Definition: fmsrcimp.cxx:61
SVX_DLLPRIVATE void BuildAndInsertFieldInfo(const css::uno::Reference< css::container::XIndexAccess > &xAllFields, sal_Int32 nField)
Definition: fmsrcimp.cxx:260
const LanguageTag & GetLanguageTag() const
class FmSearchEngine - Impl class for FmSearchDialog
FmRecordCountListener(const css::uno::Reference< css::sdbc::XResultSet > &dbcCursor)
Definition: fmsrcimp.cxx:77
Link< sal_Int32, void > m_lnkWhoWantsToKnow
Definition: fmsrcimp.hxx:74
virtual OUString getCurrentText() const override
Definition: fmsrcimp.cxx:166
CheckBoxWrapper(const css::uno::Reference< css::awt::XCheckBox > &_xBox)
Definition: fmsrcimp.cxx:172
SearchResult m_srResult
Definition: fmsrcimp.hxx:189
void SetIgnoreWidthCJK(bool bSet)
Definition: fmsrcimp.cxx:578
css::uno::Any getBookmark()
Definition: fmtools.hxx:100
#define MATCHING_WHOLETEXT
Definition: fmsrccfg.hxx:32
virtual OUString getCurrentText() const override
Definition: fmsrcimp.cxx:152
CursorWrapper m_xClonedIterator
Definition: fmsrcimp.hxx:180
Found
SVX_DLLPRIVATE bool CancelRequested()
Definition: fmsrcimp.cxx:925
void StartOverSpecial(bool _bSearchForNull)
analogous, search for "NULL" (_bSearchForNull==sal_True) or "not NULL"
Definition: fmsrcimp.cxx:1005
CharClass const m_aCharacterClassficator
Definition: fmsrcimp.hxx:163
bool is() const
Definition: fmtools.hxx:86
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: fmsrcimp.cxx:118
bool first()
Definition: fmtools.hxx:112
css::uno::Reference< css::awt::XTextComponent > m_xText
Definition: fmsrcimp.hxx:126
void SetPropChangeHandler(const Link< sal_Int32, void > &lnk)
Definition: fmsrcimp.cxx:95