xref: /aoo42x/main/sw/source/core/crsr/findtxt.cxx (revision 69a74367)
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