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