xref: /trunk/main/sw/source/core/crsr/findtxt.cxx (revision 4d7c9de063a797b8b4f3d45e3561e82ad1f8ef1f)
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_sw.hxx"
26 
27 #include <com/sun/star/util/SearchOptions.hpp>
28 #include <com/sun/star/util/SearchFlags.hpp>
29 
30 #define _SVSTDARR_USHORTS
31 #define _SVSTDARR_ULONGS
32 #include <svl/svstdarr.hxx>
33 
34 #include <vcl/svapp.hxx>
35 #include <vcl/window.hxx>
36 
37 #include <txatritr.hxx>
38 #include <fldbas.hxx>
39 #include <fmtfld.hxx>
40 #include <txtatr.hxx>
41 #include <txtfld.hxx>
42 #include <swcrsr.hxx>
43 #include <doc.hxx>
44 #include <IDocumentUndoRedo.hxx>
45 #include <pamtyp.hxx>
46 #include <ndtxt.hxx>
47 #include <swundo.hxx>
48 #include <UndoInsert.hxx>
49 #include <breakit.hxx>
50 
51 #include <docsh.hxx>
52 #include <PostItMgr.hxx>
53 #include <viewsh.hxx>
54 
55 using namespace ::com::sun::star;
56 using namespace util;
57 
58 String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam );
59 
60 
61 String& lcl_CleanStr(
62     const SwTxtNode& rNd,
63     const xub_StrLen nStart,
64     xub_StrLen& rEnde,
65     SvULongs& rArr,
66     String& rRet,
67     const bool bRemoveSoftHyphen )
68 {
69     rRet = rNd.GetTxt();
70     if( rArr.Count() )
71         rArr.Remove( 0, rArr.Count() );
72 
73     const SwpHints *pHts = rNd.GetpSwpHints();
74 
75     sal_uInt16 n = 0;
76     xub_StrLen nSoftHyphen = nStart;
77     xub_StrLen nHintStart = STRING_LEN;
78     bool bNewHint       = true;
79     bool bNewSoftHyphen = true;
80     const xub_StrLen nEnd = rEnde;
81     SvUShorts aReplaced;
82 
83     do
84     {
85         if ( bNewHint )
86             nHintStart = pHts && n < pHts->Count() ?
87                          *(*pHts)[n]->GetStart() :
88                          STRING_LEN;
89 
90         if ( bNewSoftHyphen )
91             nSoftHyphen = bRemoveSoftHyphen ?
92                           rNd.GetTxt().Search( CHAR_SOFTHYPHEN, nSoftHyphen ) :
93                           STRING_LEN;
94 
95         bNewHint       = false;
96         bNewSoftHyphen = false;
97 
98         xub_StrLen nStt = 0;
99 
100         // Check if next stop is a hint.
101         if ( STRING_LEN != nHintStart && nHintStart < nSoftHyphen && nHintStart < nEnd )
102         {
103             nStt = nHintStart;
104             bNewHint = true;
105         }
106         // Check if next stop is a soft hyphen.
107         else if ( STRING_LEN != nSoftHyphen && nSoftHyphen < nHintStart && nSoftHyphen < nEnd )
108         {
109             nStt = nSoftHyphen;
110             bNewSoftHyphen = true;
111         }
112         // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end.
113         else if ( STRING_LEN != nSoftHyphen && nSoftHyphen == nHintStart )
114         {
115             nStt = nSoftHyphen;
116             bNewHint = true;
117             bNewSoftHyphen = true;
118         }
119         else
120             break;
121 
122         const xub_StrLen nAkt = nStt - rArr.Count();
123 
124         if ( bNewHint )
125         {
126             const SwTxtAttr* pHt = (*pHts)[n];
127             if ( pHt->HasDummyChar() && (nStt >= nStart) )
128             {
129                 switch( pHt->Which() )
130                 {
131                 case RES_TXTATR_FLYCNT:
132                 case RES_TXTATR_FTN:
133                 case RES_TXTATR_FIELD:
134                 case RES_TXTATR_REFMARK:
135                 case RES_TXTATR_TOXMARK:
136                 case RES_TXTATR_META:
137                 case RES_TXTATR_METAFIELD:
138                     {
139                         sal_Bool bEmpty = RES_TXTATR_FIELD != pHt->Which() ||
140                             !(static_cast<SwTxtFld const*>(pHt)
141                                 ->GetFmtFld().GetField()->ExpandField(true).Len());
142                         if ( bEmpty && nStart == nAkt )
143                         {
144                             rArr.Insert( nAkt, rArr.Count() );
145                             --rEnde;
146                             rRet.Erase( nAkt, 1 );
147                         }
148                         else
149                         {
150                             if ( bEmpty )
151                                 aReplaced.Insert( nAkt, aReplaced.Count() );
152                             rRet.SetChar( nAkt, '\x7f' );
153                         }
154                     }
155                     break;
156                 default:
157                     ASSERT( false, "unknown case in lcl_CleanStr" )
158                     break;
159                 }
160             }
161             ++n;
162         }
163 
164         if ( bNewSoftHyphen )
165         {
166             rArr.Insert( nAkt, rArr.Count() );
167             --rEnde;
168             rRet.Erase( nAkt, 1 );
169             ++nSoftHyphen;
170         }
171     }
172     while ( true );
173 
174     for( sal_uInt16 i = aReplaced.Count(); i; )
175     {
176         const xub_StrLen nTmp = aReplaced[ --i ];
177         if( nTmp == rRet.Len() - 1 )
178         {
179             rRet.Erase( nTmp );
180             rArr.Insert( nTmp, rArr.Count() );
181             --rEnde;
182         }
183     }
184 
185     return rRet;
186 }
187 
188 // skip all non SwPostIts inside the array
189 xub_StrLen GetPostIt(xub_StrLen aCount,const SwpHints *pHts)
190 {
191     xub_StrLen aIndex = 0;
192     while (aCount)
193     {
194         for (xub_StrLen i = 0; i <pHts->Count();i++)
195         {
196             aIndex++;
197             const SwTxtAttr* pTxtAttr = (*pHts)[i];
198             if ( (pTxtAttr->Which()==RES_TXTATR_FIELD)
199                  && (pTxtAttr->GetFmtFld().GetField()->Which()==RES_POSTITFLD))
200             {
201                 aCount--;
202                 if (!aCount)
203                     break;
204             }
205         }
206     }
207     // throw away all following non postits
208     for (xub_StrLen i = aIndex; i <pHts->Count();i++)
209     {
210         const SwTxtAttr* pTxtAttr = (*pHts)[i];
211         if ( (pTxtAttr->Which()==RES_TXTATR_FIELD)
212              && (pTxtAttr->GetFmtFld().GetField()->Which()==RES_POSTITFLD))
213             break;
214         else
215             aIndex++;
216     }
217     return aIndex;
218 }
219 
220 sal_uInt8 SwPaM::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes , utl::TextSearch& rSTxt,
221                     SwMoveFn fnMove, const SwPaM * pRegion,
222                     sal_Bool bInReadOnly )
223 {
224     if( !rSearchOpt.searchString.getLength() )
225         return sal_False;
226 
227     SwPaM* pPam = MakeRegion( fnMove, pRegion );
228     sal_Bool bSrchForward = fnMove == fnMoveForward;
229     SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
230     SwIndex& rCntntIdx = pPam->GetPoint()->nContent;
231 
232     // Wenn am Anfang/Ende, aus dem Node moven
233     // beim leeren Node nicht weiter
234     if( bSrchForward
235         ? ( rCntntIdx.GetIndex() == pPam->GetCntntNode()->Len() &&
236             rCntntIdx.GetIndex() )
237         : !rCntntIdx.GetIndex() && pPam->GetCntntNode()->Len() )
238     {
239         if( !(*fnMove->fnNds)( &rNdIdx, sal_False ))
240         {
241             delete pPam;
242             return sal_False;
243         }
244         SwCntntNode *pNd = rNdIdx.GetNode().GetCntntNode();
245         xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
246         rCntntIdx.Assign( pNd, nTmpPos );
247     }
248 
249     /*
250      * Ist bFound == sal_True, dann wurde der String gefunden und in
251      * nStart und nEnde steht der gefundenen String
252      */
253     sal_Bool bFound = sal_False;
254     /*
255      * StartPostion im Text oder Anfangsposition
256      */
257     sal_Bool bFirst = sal_True;
258     SwCntntNode * pNode;
259     //testarea
260     //String sCleanStr;
261     //SvULongs aFltArr;
262     //const SwNode* pSttNd = &rNdIdx.GetNode();
263 
264     xub_StrLen nStart, nEnde, nTxtLen;
265 
266     sal_Bool bRegSearch = SearchAlgorithms_REGEXP == rSearchOpt.algorithmType;
267     sal_Bool bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() &&
268                         ( !rSearchOpt.searchString.compareToAscii( "^$" ) ||
269                           !rSearchOpt.searchString.compareToAscii( "$^" ) );
270     sal_Bool bChkParaEnd = bRegSearch && 1 == rSearchOpt.searchString.getLength() &&
271                       !rSearchOpt.searchString.compareToAscii( "$" );
272 
273 //    LanguageType eLastLang = 0;
274     while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ))
275     {
276         if( pNode->IsTxtNode() )
277         {
278             nTxtLen = ((SwTxtNode*)pNode)->GetTxt().Len();
279             if( rNdIdx == pPam->GetMark()->nNode )
280                 nEnde = pPam->GetMark()->nContent.GetIndex();
281             else
282                 nEnde = bSrchForward ? nTxtLen : 0;
283             nStart = rCntntIdx.GetIndex();
284 
285             /* #i80135# */
286             // if there are SwPostItFields inside our current node text, we split the text into seperate pieces
287             // and search for text inside the pieces as well as inside the fields
288             const SwpHints *pHts = ((SwTxtNode*)pNode)->GetpSwpHints();
289 
290             // count postitfields by looping over all fields
291             xub_StrLen aNumberPostits = 0;
292             xub_StrLen aIgnore = 0;
293             if (pHts && bSearchInNotes)
294             {
295                 if (!bSrchForward)
296                 {
297                     xub_StrLen swap = nEnde;
298                     nEnde = nStart;
299                     nStart = swap;
300                 }
301 
302                 for (xub_StrLen i = 0; i <pHts->Count();i++)
303                 {
304                     const xub_StrLen aPos = *(*pHts)[i]->GetStart();
305                     const SwTxtAttr* pTxtAttr = (*pHts)[i];
306                     if ( (pTxtAttr->Which()==RES_TXTATR_FIELD)
307                          && (pTxtAttr->GetFmtFld().GetField()->Which()==RES_POSTITFLD))
308                     {
309                         if ( (aPos >= nStart) && (aPos <= nEnde) )
310                             aNumberPostits++;
311                         else
312                         {
313                             if (bSrchForward)
314                                 aIgnore++;
315                         }
316                     }
317                 }
318 
319                 if (!bSrchForward)
320                 {
321                     xub_StrLen swap = nEnde;
322                     nEnde = nStart;
323                     nStart = swap;
324                 }
325 
326             }
327 
328             SwDocShell *const pDocShell = pNode->GetDoc()->GetDocShell();
329             ViewShell *const pWrtShell = (pDocShell) ? (ViewShell*)(pDocShell->GetWrtShell()) : 0;
330             SwPostItMgr *const pPostItMgr = (pWrtShell) ? pWrtShell->GetPostItMgr() : 0;
331 
332             xub_StrLen aStart = 0;
333             // do we need to finish a note?
334             if (pPostItMgr && pPostItMgr->HasActiveSidebarWin())
335             {
336                 if (bSearchInNotes)
337                 {
338                     if (bSrchForward)
339                         aStart++;
340                     else
341                     {
342                         if (aNumberPostits)
343                             --aNumberPostits;
344                     }
345                     //search inside and finsih and put focus back into the doc
346                     if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward))
347                     {
348                         bFound = true ;
349                         break;
350                     }
351                 }
352                 else
353                 {
354                     pPostItMgr->SetActiveSidebarWin(0);
355                 }
356             }
357 
358             if (aNumberPostits)
359             {
360                 // now we have to split
361                 xub_StrLen nStartInside = 0;
362                 xub_StrLen nEndeInside = 0;
363                 sal_Int16 aLoop= bSrchForward ? aStart : aNumberPostits;
364 
365                 while ( (aLoop>=0) && (aLoop<=aNumberPostits))
366                 {
367                     if (bSrchForward)
368                     {
369                         nStartInside =  aLoop==0 ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
370                         nEndeInside = aLoop==aNumberPostits? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
371                         nTxtLen = nEndeInside-nStartInside;
372                     }
373                     else
374                     {
375                         nStartInside =  aLoop==aNumberPostits ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
376                         nEndeInside = aLoop==0 ? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
377                         nTxtLen = nStartInside-nEndeInside;
378                     }
379                     // search inside the text between a note
380                     bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd,
381                                 nStartInside,nEndeInside,nTxtLen, pNode,pPam);
382                     if (bFound)
383                         break;
384                     else
385                     {
386                         // we should now be right in front of a note, search inside
387                         if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) ))
388                         {
389                             const SwTxtAttr* pTxtAttr = bSrchForward ?  (*pHts)[GetPostIt(aLoop+aIgnore,pHts)] : (*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)];
390                             if ( pPostItMgr && pPostItMgr->SearchReplace(((SwTxtFld*)pTxtAttr)->GetFmtFld(),rSearchOpt,bSrchForward) )
391                             {
392                                 bFound = true ;
393                                 break;
394                             }
395                         }
396                     }
397                     aLoop = bSrchForward ? aLoop+1 : aLoop-1;
398                 }
399             }
400             else
401             {
402                 // if there is no SwPostItField inside or searching inside notes is disabled, we search the whole length just like before
403                 bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd,
404                             nStart,nEnde,nTxtLen, pNode,pPam);
405             }
406             if (bFound)
407                 break;
408         }
409     }
410     delete pPam;
411     return bFound;
412 }
413 
414 bool SwPaM::DoSearch( const SearchOptions& rSearchOpt, utl::TextSearch& rSTxt,
415                     SwMoveFn fnMove,
416                     sal_Bool bSrchForward, sal_Bool bRegSearch, sal_Bool bChkEmptyPara, sal_Bool bChkParaEnd,
417                     xub_StrLen &nStart, xub_StrLen &nEnde, xub_StrLen nTxtLen,SwNode* pNode, SwPaM* pPam)
418 {
419     bool bFound = false;
420     SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
421     const SwNode* pSttNd = &rNdIdx.GetNode();
422     String sCleanStr;
423     SvULongs aFltArr;
424     LanguageType eLastLang = 0;
425     // if the search string contains a soft hypen, we don't strip them from the text:
426     bool bRemoveSoftHyphens = true;
427     if ( bRegSearch )
428     {
429         const rtl::OUString a00AD( rtl::OUString::createFromAscii( "\\x00AD" ) );
430         if ( -1 != rSearchOpt.searchString.indexOf( a00AD ) )
431              bRemoveSoftHyphens = false;
432     }
433     else
434     {
435         if ( 1 == rSearchOpt.searchString.getLength() &&
436              CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() )
437              bRemoveSoftHyphens = false;
438     }
439 
440     if( bSrchForward )
441         lcl_CleanStr( *(SwTxtNode*)pNode, nStart, nEnde,
442                         aFltArr, sCleanStr, bRemoveSoftHyphens );
443     else
444         lcl_CleanStr( *(SwTxtNode*)pNode, nEnde, nStart,
445                         aFltArr, sCleanStr, bRemoveSoftHyphens );
446 
447     SwScriptIterator* pScriptIter = 0;
448     sal_uInt16 nSearchScript = 0;
449     sal_uInt16 nCurrScript = 0;
450 
451     if ( SearchAlgorithms_APPROXIMATE == rSearchOpt.algorithmType &&
452          pBreakIt->GetBreakIter().is() )
453     {
454         pScriptIter = new SwScriptIterator( sCleanStr, nStart, bSrchForward );
455         nSearchScript = pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 );
456     }
457 
458     xub_StrLen nStringEnd = nEnde;
459     while ( (bSrchForward && nStart < nStringEnd) ||
460             (! bSrchForward && nStart > nStringEnd) )
461     {
462         // SearchAlgorithms_APPROXIMATE works on a per word base
463         // so we have to provide the text searcher with the correct
464         // locale, because it uses the breakiterator
465         if ( pScriptIter )
466         {
467             nEnde = pScriptIter->GetScriptChgPos();
468             nCurrScript = pScriptIter->GetCurrScript();
469             if ( nSearchScript == nCurrScript )
470             {
471                 const LanguageType eCurrLang =
472                         ((SwTxtNode*)pNode)->GetLang( bSrchForward ?
473                                                       nStart :
474                                                       nEnde );
475 
476                 if ( eCurrLang != eLastLang )
477                 {
478                     const lang::Locale aLocale(
479                             pBreakIt->GetLocale( eCurrLang ) );
480                     rSTxt.SetLocale( rSearchOpt, aLocale );
481                     eLastLang = eCurrLang;
482                 }
483             }
484             pScriptIter->Next();
485         }
486 
487         if( nSearchScript == nCurrScript &&
488             (rSTxt.*fnMove->fnSearch)( sCleanStr, &nStart, &nEnde, 0 ))
489         {
490             // setze den Bereich richtig
491             *GetPoint() = *pPam->GetPoint();
492             SetMark();
493 
494             // Start und Ende wieder korrigieren !!
495             if( aFltArr.Count() )
496             {
497                 xub_StrLen n, nNew;
498                 // bei Rueckwaertssuche die Positionen temp. vertauschen
499                 if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; }
500 
501                 for( n = 0, nNew = nStart;
502                     n < aFltArr.Count() && aFltArr[ n ] <= nStart;
503                     ++n, ++nNew )
504                     ;
505                 nStart = nNew;
506                 for( n = 0, nNew = nEnde;
507                     n < aFltArr.Count() && aFltArr[ n ] < nEnde;
508                     ++n, ++nNew )
509                     ;
510                 nEnde = nNew;
511 
512                 // bei Rueckwaertssuche die Positionen temp. vertauschen
513                 if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; }
514             }
515             GetMark()->nContent = nStart;       // Startposition setzen
516             GetPoint()->nContent = nEnde;
517 
518             if( !bSrchForward )         // rueckwaerts Suche?
519                 Exchange();             // Point und Mark tauschen
520             bFound = sal_True;
521             break;
522         }
523 
524         nStart = nEnde;
525     } // end of script while
526 
527     delete pScriptIter;
528 
529     if ( bFound )
530         return true;
531     else if( ( bChkEmptyPara && !nStart && !nTxtLen ) || bChkParaEnd )
532     {
533         *GetPoint() = *pPam->GetPoint();
534         GetPoint()->nContent = bChkParaEnd ? nTxtLen : 0;
535         SetMark();
536         if( (bSrchForward || pSttNd != &rNdIdx.GetNode()) &&
537             Move( fnMoveForward, fnGoCntnt ) &&
538             (!bSrchForward || pSttNd != &GetPoint()->nNode.GetNode()) &&
539             1 == Abs( (int)( GetPoint()->nNode.GetIndex() -
540                             GetMark()->nNode.GetIndex()) ) )
541         {
542             if( !bSrchForward )         // rueckwaerts Suche?
543                 Exchange();             // Point und Mark tauschen
544             //bFound = sal_True;
545             //break;
546             return true;
547         }
548     }
549     return bFound;
550 }
551 
552 // Parameter fuers Suchen und Ersetzen von Text
553 struct SwFindParaText : public SwFindParas
554 {
555     const SearchOptions& rSearchOpt;
556     SwCursor& rCursor;
557     utl::TextSearch aSTxt;
558     sal_Bool bReplace;
559     sal_Bool bSearchInNotes;
560 
561     SwFindParaText( const SearchOptions& rOpt, sal_Bool bSearchNotes, int bRepl, SwCursor& rCrsr )
562         : rSearchOpt( rOpt ), rCursor( rCrsr ), aSTxt( rOpt ), bReplace( 0 != bRepl ), bSearchInNotes( bSearchNotes )
563     {}
564     virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
565     virtual int IsReplaceMode() const;
566     virtual ~SwFindParaText();
567 };
568 
569 SwFindParaText::~SwFindParaText()
570 {
571 }
572 
573 int SwFindParaText::Find( SwPaM* pCrsr, SwMoveFn fnMove,
574                             const SwPaM* pRegion, sal_Bool bInReadOnly )
575 {
576     if( bInReadOnly && bReplace )
577         bInReadOnly = sal_False;
578 
579     sal_Bool bFnd = (sal_Bool)pCrsr->Find( rSearchOpt, bSearchInNotes, aSTxt, fnMove, pRegion, bInReadOnly );
580 
581     /*   #i80135# if we found something in a note, Mark and Point is the same
582     if( bFnd && *pCrsr->GetMark() == *pCrsr->GetPoint() )
583         return FIND_NOT_FOUND;
584     */
585 
586     if( bFnd && bReplace )          // String ersetzen ??
587     {
588         // Replace-Methode vom SwDoc benutzen
589         const bool bRegExp(SearchAlgorithms_REGEXP == rSearchOpt.algorithmType);
590         SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
591         xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
592         // damit die Region auch verschoben wird, in den Shell-Cursr-Ring
593         // mit aufnehmen !!
594         Ring *pPrev(0);
595         if( bRegExp )
596         {
597             pPrev = pRegion->GetPrev();
598             ((Ring*)pRegion)->MoveRingTo( &rCursor );
599         }
600 
601         ::std::auto_ptr<String> pRepl( (bRegExp)
602                 ? ReplaceBackReferences( rSearchOpt, pCrsr ) : 0 );
603         rCursor.GetDoc()->ReplaceRange( *pCrsr,
604             (pRepl.get()) ? *pRepl : String(rSearchOpt.replaceString),
605             bRegExp );
606         rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
607 
608         if( bRegExp )
609         {
610             // und die Region wieder herausnehmen:
611             Ring *p, *pNext = (Ring*)pRegion;
612             do {
613                 p = pNext;
614                 pNext = p->GetNext();
615                 p->MoveTo( (Ring*)pRegion );
616             } while( p != pPrev );
617         }
618         pCrsr->Start()->nContent = nSttCnt;
619         return FIND_NO_RING;
620     }
621     return bFnd ? FIND_FOUND : FIND_NOT_FOUND;
622 }
623 
624 
625 int SwFindParaText::IsReplaceMode() const
626 {
627     return bReplace;
628 }
629 
630 
631 sal_uLong SwCursor::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes,
632                         SwDocPositions nStart, SwDocPositions nEnde,
633                         sal_Bool& bCancel,
634                         FindRanges eFndRngs, int bReplace )
635 {
636     // OLE-Benachrichtigung abschalten !!
637     SwDoc* pDoc = GetDoc();
638     Link aLnk( pDoc->GetOle2Link() );
639     pDoc->SetOle2Link( Link() );
640 
641     bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
642     if (bStartUndo)
643     {
644         pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
645     }
646 
647     sal_Bool bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE);
648     if( bSearchSel )
649         eFndRngs = (FindRanges)(eFndRngs | FND_IN_SEL);
650     SwFindParaText aSwFindParaText( rSearchOpt, bSearchInNotes, bReplace, *this );
651     sal_uLong nRet = FindAll( aSwFindParaText, nStart, nEnde, eFndRngs, bCancel );
652     pDoc->SetOle2Link( aLnk );
653     if( nRet && bReplace )
654         pDoc->SetModified();
655 
656     if (bStartUndo)
657     {
658         SwRewriter rewriter(MakeUndoReplaceRewriter(
659                 nRet, rSearchOpt.searchString, rSearchOpt.replaceString));
660         pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, & rewriter );
661     }
662     return nRet;
663 }
664 
665 String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam )
666 {
667     String *pRet = 0;
668     if( pPam && pPam->HasMark() &&
669         SearchAlgorithms_REGEXP == rSearchOpt.algorithmType )
670     {
671         const SwCntntNode* pTxtNode = pPam->GetCntntNode( sal_True );
672         if( pTxtNode && pTxtNode->IsTxtNode() && pTxtNode == pPam->GetCntntNode( sal_False ) )
673         {
674             utl::TextSearch aSTxt( rSearchOpt );
675             const String& rStr = static_cast<const SwTxtNode*>(pTxtNode)->GetTxt();
676             xub_StrLen nStart = pPam->Start()->nContent.GetIndex();
677             xub_StrLen nEnd = pPam->End()->nContent.GetIndex();
678             SearchResult aResult;
679             if( aSTxt.SearchFrwrd( rStr, &nStart, &nEnd, &aResult ) )
680             {
681                 String aReplaceStr( rSearchOpt.replaceString );
682                 aSTxt.ReplaceBackReferences( aReplaceStr, rStr, aResult );
683                 pRet = new String( aReplaceStr );
684             }
685         }
686     }
687     return pRet;
688 }
689