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