xref: /aoo41x/main/sw/source/core/crsr/findtxt.cxx (revision c0286415)
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(
61     const SwTxtNode& rNd,
62     xub_StrLen nStart,
63     xub_StrLen& rEnde,
64     SvULongs& rArr,
65     String& rRet,
66     const 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                                 ->GetFmtFld().GetField()->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->GetFmtFld().GetField()->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->GetFmtFld().GetField()->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->GetFmtFld().GetField()->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)->GetFmtFld(),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             const String& rStr = static_cast<const SwTxtNode*>(pTxtNode)->GetTxt();
684 			xub_StrLen nStart = pPam->Start()->nContent.GetIndex();
685 			xub_StrLen nEnd = pPam->End()->nContent.GetIndex();
686             SearchResult aResult;
687             if( aSTxt.SearchFrwrd( rStr, &nStart, &nEnd, &aResult ) )
688             {
689                 String aReplaceStr( rSearchOpt.replaceString );
690                 aSTxt.ReplaceBackReferences( aReplaceStr, rStr, aResult );
691                 pRet = new String( aReplaceStr );
692             }
693         }
694     }
695     return pRet;
696 }
697