xref: /aoo42x/main/sw/source/core/crsr/findtxt.cxx (revision e926d11b)
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             const String& rStr = static_cast<const SwTxtNode*>(pTxtNode)->GetTxt();
680 			xub_StrLen nStart = pPam->Start()->nContent.GetIndex();
681 			xub_StrLen nEnd = pPam->End()->nContent.GetIndex();
682             SearchResult aResult;
683             if( aSTxt.SearchFrwrd( rStr, &nStart, &nEnd, &aResult ) )
684             {
685                 String aReplaceStr( rSearchOpt.replaceString );
686                 aSTxt.ReplaceBackReferences( aReplaceStr, rStr, aResult );
687                 pRet = new String( aReplaceStr );
688             }
689         }
690     }
691     return pRet;
692 }
693