merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / crsr / findtxt.cxx
blobab93dee334bb5d67a71be09839a60095f2b48107
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: findtxt.cxx,v $
10 * $Revision: 1.24 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <com/sun/star/util/SearchOptions.hpp>
34 #include <com/sun/star/util/SearchFlags.hpp>
38 #define _SVSTDARR_USHORTS
39 #define _SVSTDARR_ULONGS
40 #include <svtools/svstdarr.hxx>
41 #include <vcl/svapp.hxx>
42 #include <txatritr.hxx>
43 #include <fldbas.hxx>
44 #include <fmtfld.hxx>
45 #include <txtatr.hxx>
46 #include <txtfld.hxx>
47 #include <swcrsr.hxx>
48 #include <doc.hxx>
49 #include <pamtyp.hxx>
50 #include <ndtxt.hxx>
51 #include <swundo.hxx>
52 #include <breakit.hxx>
54 /*testarea*/
55 #include <docsh.hxx>
56 #include <PostItMgr.hxx>
57 #include <viewsh.hxx>
58 #include <vcl/window.hxx>
60 #define POSTITMGR ((ViewShell*)pNode->GetDoc()->GetDocShell()->GetWrtShell())->GetPostItMgr()
62 using namespace ::com::sun::star;
63 using namespace util;
65 String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam );
67 String& lcl_CleanStr( const SwTxtNode& rNd, xub_StrLen nStart,
68 xub_StrLen& rEnde, SvULongs& rArr, String& rRet,
69 bool bRemoveSoftHyphen )
71 rRet = rNd.GetTxt();
72 if( rArr.Count() )
73 rArr.Remove( 0, rArr.Count() );
75 const SwpHints *pHts = rNd.GetpSwpHints();
77 USHORT n = 0;
78 xub_StrLen nSoftHyphen = nStart;
79 xub_StrLen nHintStart = STRING_LEN;
80 bool bNewHint = true;
81 bool bNewSoftHyphen = true;
82 const xub_StrLen nEnd = rEnde;
83 SvUShorts aReplaced;
87 if ( bNewHint )
88 nHintStart = pHts && n < pHts->Count() ?
89 *(*pHts)[n]->GetStart() :
90 STRING_LEN;
92 if ( bNewSoftHyphen )
93 nSoftHyphen = bRemoveSoftHyphen ?
94 rNd.GetTxt().Search( CHAR_SOFTHYPHEN, nSoftHyphen ) :
95 STRING_LEN;
97 bNewHint = false;
98 bNewSoftHyphen = false;
100 xub_StrLen nStt = 0;
102 // Check if next stop is a hint.
103 if ( STRING_LEN != nHintStart && nHintStart < nSoftHyphen && nHintStart < nEnd )
105 nStt = nHintStart;
106 bNewHint = true;
108 // Check if next stop is a soft hyphen.
109 else if ( STRING_LEN != nSoftHyphen && nSoftHyphen < nHintStart && nSoftHyphen < nEnd )
111 nStt = nSoftHyphen;
112 bNewSoftHyphen = true;
114 // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end.
115 else if ( STRING_LEN != nSoftHyphen && nSoftHyphen == nHintStart )
117 nStt = nSoftHyphen;
118 bNewHint = true;
119 bNewSoftHyphen = true;
121 else
122 break;
124 const xub_StrLen nAkt = nStt - rArr.Count();
126 if ( bNewHint )
128 const SwTxtAttr* pHt = (*pHts)[n];
129 if ( pHt->HasDummyChar() && (nStt >= nStart) )
131 //JP 17.05.00: Task 75806 ask for ">=" and not for ">"
132 switch( pHt->Which() )
134 case RES_TXTATR_FLYCNT:
135 case RES_TXTATR_FTN:
136 case RES_TXTATR_FIELD:
137 case RES_TXTATR_REFMARK:
138 case RES_TXTATR_TOXMARK:
139 case RES_TXTATR_META:
140 case RES_TXTATR_METAFIELD:
142 // JP 06.05.98: mit Bug 50100 werden sie als Trenner erwuenscht und nicht
143 // mehr zum Wort dazu gehoerend.
144 // MA 23.06.98: mit Bug 51215 sollen sie konsequenterweise auch am
145 // Satzanfang und -ende ignoriert werden wenn sie Leer sind.
146 // Dazu werden sie schlicht entfernt. Fuer den Anfang entfernen
147 // wir sie einfach.
148 // Fuer das Ende merken wir uns die Ersetzungen und entferenen
149 // hinterher alle am Stringende (koenten ja 'normale' 0x7f drinstehen
150 BOOL bEmpty = RES_TXTATR_FIELD != pHt->Which() ||
151 !((SwTxtFld*)pHt)->GetFld().GetFld()->Expand().Len();
152 if ( bEmpty && nStart == nAkt )
154 rArr.Insert( nAkt, rArr.Count() );
155 --rEnde;
156 rRet.Erase( nAkt, 1 );
158 else
160 if ( bEmpty )
161 aReplaced.Insert( nAkt, aReplaced.Count() );
162 rRet.SetChar( nAkt, '\x7f' );
165 break;
166 default:
167 ASSERT( false, "unknown case in lcl_CleanStr" )
168 break;
171 ++n;
174 if ( bNewSoftHyphen )
176 rArr.Insert( nAkt, rArr.Count() );
177 --rEnde;
178 rRet.Erase( nAkt, 1 );
179 ++nSoftHyphen;
182 while ( true );
184 for( USHORT i = aReplaced.Count(); i; )
186 const xub_StrLen nTmp = aReplaced[ --i ];
187 if( nTmp == rRet.Len() - 1 )
189 rRet.Erase( nTmp );
190 rArr.Insert( nTmp, rArr.Count() );
191 --rEnde;
195 return rRet;
198 // skip all non SwPostIts inside the array
199 xub_StrLen GetPostIt(xub_StrLen aCount,const SwpHints *pHts)
201 xub_StrLen aIndex = 0;
202 while (aCount)
204 for (xub_StrLen i = 0; i <pHts->Count();i++)
206 aIndex++;
207 const SwTxtAttr* pTxtAttr = (*pHts)[i];
208 if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
209 (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
211 aCount--;
212 if (!aCount)
213 break;
217 // throw away all following non postits
218 for (xub_StrLen i = aIndex; i <pHts->Count();i++)
220 const SwTxtAttr* pTxtAttr = (*pHts)[i];
221 if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
222 (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
223 break;
224 else
225 aIndex++;
227 return aIndex;
230 BYTE SwPaM::Find( const SearchOptions& rSearchOpt, BOOL bSearchInNotes , utl::TextSearch& rSTxt,
231 SwMoveFn fnMove, const SwPaM * pRegion,
232 BOOL bInReadOnly )
234 if( !rSearchOpt.searchString.getLength() )
235 return FALSE;
237 SwPaM* pPam = MakeRegion( fnMove, pRegion );
238 BOOL bSrchForward = fnMove == fnMoveForward;
239 SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
240 SwIndex& rCntntIdx = pPam->GetPoint()->nContent;
242 // Wenn am Anfang/Ende, aus dem Node moven
243 // beim leeren Node nicht weiter
244 if( bSrchForward
245 ? ( rCntntIdx.GetIndex() == pPam->GetCntntNode()->Len() &&
246 rCntntIdx.GetIndex() )
247 : !rCntntIdx.GetIndex() && pPam->GetCntntNode()->Len() )
249 if( !(*fnMove->fnNds)( &rNdIdx, FALSE ))
251 delete pPam;
252 return FALSE;
254 SwCntntNode *pNd = rNdIdx.GetNode().GetCntntNode();
255 xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
256 rCntntIdx.Assign( pNd, nTmpPos );
260 * Ist bFound == TRUE, dann wurde der String gefunden und in
261 * nStart und nEnde steht der gefundenen String
263 BOOL bFound = FALSE;
265 * StartPostion im Text oder Anfangsposition
267 BOOL bFirst = TRUE;
268 SwCntntNode * pNode;
269 //testarea
270 //String sCleanStr;
271 //SvULongs aFltArr;
272 //const SwNode* pSttNd = &rNdIdx.GetNode();
274 xub_StrLen nStart, nEnde, nTxtLen;
276 BOOL bRegSearch = SearchAlgorithms_REGEXP == rSearchOpt.algorithmType;
277 BOOL bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() &&
278 ( !rSearchOpt.searchString.compareToAscii( "^$" ) ||
279 !rSearchOpt.searchString.compareToAscii( "$^" ) );
280 BOOL bChkParaEnd = bRegSearch && 1 == rSearchOpt.searchString.getLength() &&
281 !rSearchOpt.searchString.compareToAscii( "$" );
283 // LanguageType eLastLang = 0;
284 while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ))
286 if( pNode->IsTxtNode() )
288 nTxtLen = ((SwTxtNode*)pNode)->GetTxt().Len();
289 if( rNdIdx == pPam->GetMark()->nNode )
290 nEnde = pPam->GetMark()->nContent.GetIndex();
291 else
292 nEnde = bSrchForward ? nTxtLen : 0;
293 nStart = rCntntIdx.GetIndex();
295 /* #i80135# */
296 // if there are SwPostItFields inside our current node text, we split the text into seperate pieces
297 // and search for text inside the pieces as well as inside the fields
298 const SwpHints *pHts = ((SwTxtNode*)pNode)->GetpSwpHints();
300 // count postitfields by looping over all fields
301 xub_StrLen aNumberPostits = 0;
302 xub_StrLen aIgnore = 0;
303 if (pHts && bSearchInNotes)
305 if (!bSrchForward)
307 xub_StrLen swap = nEnde;
308 nEnde = nStart;
309 nStart = swap;
312 for (xub_StrLen i = 0; i <pHts->Count();i++)
314 xub_StrLen aPos = *(*pHts)[i]->GetStart();
315 const SwTxtAttr* pTxtAttr = (*pHts)[i];
316 if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
317 (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
319 if ( (aPos >= nStart) && (aPos <= nEnde) )
320 aNumberPostits++;
321 else
323 if (bSrchForward)
324 aIgnore++;
329 if (!bSrchForward)
331 xub_StrLen swap = nEnde;
332 nEnde = nStart;
333 nStart = swap;
338 xub_StrLen aStart = 0;
339 // do we need to finish a note?
340 if (POSTITMGR->GetActivePostIt())
342 if (bSearchInNotes)
344 if (bSrchForward)
345 aStart++;
346 else
348 if (aNumberPostits)
349 --aNumberPostits;
351 //search inside and finsih and put focus back into the doc
352 if (POSTITMGR->FinishSearchReplace(rSearchOpt,bSrchForward))
354 bFound = true ;
355 break;
358 else
360 POSTITMGR->SetActivePostIt(0);
364 if (aNumberPostits)
366 // now we have to split
367 xub_StrLen nStartInside = 0;
368 xub_StrLen nEndeInside = 0;
369 sal_Int16 aLoop= bSrchForward ? aStart : aNumberPostits;
371 while ( (aLoop>=0) && (aLoop<=aNumberPostits))
373 if (bSrchForward)
375 nStartInside = aLoop==0 ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
376 nEndeInside = aLoop==aNumberPostits? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
377 nTxtLen = nEndeInside-nStartInside;
379 else
381 nStartInside = aLoop==aNumberPostits ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
382 nEndeInside = aLoop==0 ? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
383 nTxtLen = nStartInside-nEndeInside;
385 // search inside the text between a note
386 bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd,
387 nStartInside,nEndeInside,nTxtLen, pNode,pPam);
388 if (bFound)
389 break;
390 else
392 // we should now be right in front of a note, search inside
393 if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) ))
395 const SwTxtAttr* pTxtAttr = bSrchForward ? (*pHts)[GetPostIt(aLoop+aIgnore,pHts)] : (*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)];
396 if ( POSTITMGR->SearchReplace(((SwTxtFld*)pTxtAttr)->GetFld(),rSearchOpt,bSrchForward) )
398 bFound = true ;
399 break;
403 aLoop = bSrchForward ? aLoop+1 : aLoop-1;
406 else
408 // if there is no SwPostItField inside or searching inside notes is disabled, we search the whole length just like before
409 bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd,
410 nStart,nEnde,nTxtLen, pNode,pPam);
412 if (bFound)
413 break;
416 delete pPam;
417 return bFound;
420 bool SwPaM::DoSearch( const SearchOptions& rSearchOpt, utl::TextSearch& rSTxt,
421 SwMoveFn fnMove,
422 BOOL bSrchForward, BOOL bRegSearch, BOOL bChkEmptyPara, BOOL bChkParaEnd,
423 xub_StrLen &nStart, xub_StrLen &nEnde, xub_StrLen nTxtLen,SwNode* pNode, SwPaM* pPam)
425 bool bFound = false;
426 SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
427 const SwNode* pSttNd = &rNdIdx.GetNode();
428 String sCleanStr;
429 SvULongs aFltArr;
430 LanguageType eLastLang = 0;
431 // if the search string contains a soft hypen, we don't strip them from the text:
432 bool bRemoveSoftHyphens = true;
433 if ( bRegSearch )
435 const rtl::OUString a00AD( rtl::OUString::createFromAscii( "\\x00AD" ) );
436 if ( -1 != rSearchOpt.searchString.indexOf( a00AD ) )
437 bRemoveSoftHyphens = false;
439 else
441 if ( 1 == rSearchOpt.searchString.getLength() &&
442 CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() )
443 bRemoveSoftHyphens = false;
446 if( bSrchForward )
447 lcl_CleanStr( *(SwTxtNode*)pNode, nStart, nEnde,
448 aFltArr, sCleanStr, bRemoveSoftHyphens );
449 else
450 lcl_CleanStr( *(SwTxtNode*)pNode, nEnde, nStart,
451 aFltArr, sCleanStr, bRemoveSoftHyphens );
453 SwScriptIterator* pScriptIter = 0;
454 USHORT nSearchScript = 0;
455 USHORT nCurrScript = 0;
457 if ( SearchAlgorithms_APPROXIMATE == rSearchOpt.algorithmType &&
458 pBreakIt->GetBreakIter().is() )
460 pScriptIter = new SwScriptIterator( sCleanStr, nStart, bSrchForward );
461 nSearchScript = pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 );
464 xub_StrLen nStringEnd = nEnde;
465 while ( (bSrchForward && nStart < nStringEnd) ||
466 (! bSrchForward && nStart > nStringEnd) )
468 // SearchAlgorithms_APPROXIMATE works on a per word base
469 // so we have to provide the text searcher with the correct
470 // locale, because it uses the breakiterator
471 if ( pScriptIter )
473 nEnde = pScriptIter->GetScriptChgPos();
474 nCurrScript = pScriptIter->GetCurrScript();
475 if ( nSearchScript == nCurrScript )
477 const LanguageType eCurrLang =
478 ((SwTxtNode*)pNode)->GetLang( bSrchForward ?
479 nStart :
480 nEnde );
482 if ( eCurrLang != eLastLang )
484 const lang::Locale aLocale(
485 pBreakIt->GetLocale( eCurrLang ) );
486 rSTxt.SetLocale( rSearchOpt, aLocale );
487 eLastLang = eCurrLang;
490 pScriptIter->Next();
493 if( nSearchScript == nCurrScript &&
494 (rSTxt.*fnMove->fnSearch)( sCleanStr, &nStart, &nEnde, 0 ))
496 // setze den Bereich richtig
497 *GetPoint() = *pPam->GetPoint();
498 SetMark();
500 // Start und Ende wieder korrigieren !!
501 if( aFltArr.Count() )
503 xub_StrLen n, nNew;
504 // bei Rueckwaertssuche die Positionen temp. vertauschen
505 if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; }
507 for( n = 0, nNew = nStart;
508 n < aFltArr.Count() && aFltArr[ n ] <= nStart;
509 ++n, ++nNew )
511 nStart = nNew;
512 for( n = 0, nNew = nEnde;
513 n < aFltArr.Count() && aFltArr[ n ] < nEnde;
514 ++n, ++nNew )
516 nEnde = nNew;
518 // bei Rueckwaertssuche die Positionen temp. vertauschen
519 if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; }
521 GetMark()->nContent = nStart; // Startposition setzen
522 GetPoint()->nContent = nEnde;
524 if( !bSrchForward ) // rueckwaerts Suche?
525 Exchange(); // Point und Mark tauschen
526 bFound = TRUE;
527 break;
530 nStart = nEnde;
531 } // end of script while
533 delete pScriptIter;
535 if ( bFound )
536 return true;
537 else if( ( bChkEmptyPara && !nStart && !nTxtLen ) || bChkParaEnd )
539 *GetPoint() = *pPam->GetPoint();
540 GetPoint()->nContent = bChkParaEnd ? nTxtLen : 0;
541 SetMark();
542 if( (bSrchForward || pSttNd != &rNdIdx.GetNode()) &&
543 Move( fnMoveForward, fnGoCntnt ) &&
544 (!bSrchForward || pSttNd != &GetPoint()->nNode.GetNode()) &&
545 1 == Abs( (int)( GetPoint()->nNode.GetIndex() -
546 GetMark()->nNode.GetIndex()) ) )
548 if( !bSrchForward ) // rueckwaerts Suche?
549 Exchange(); // Point und Mark tauschen
550 //bFound = TRUE;
551 //break;
552 return true;
555 return bFound;
558 // Parameter fuers Suchen und Ersetzen von Text
559 struct SwFindParaText : public SwFindParas
561 const SearchOptions& rSearchOpt;
562 SwCursor& rCursor;
563 utl::TextSearch aSTxt;
564 BOOL bReplace;
565 BOOL bSearchInNotes;
567 SwFindParaText( const SearchOptions& rOpt, BOOL bSearchNotes, int bRepl, SwCursor& rCrsr )
568 : rSearchOpt( rOpt ), rCursor( rCrsr ), aSTxt( rOpt ), bReplace( 0 != bRepl ), bSearchInNotes( bSearchNotes )
570 virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, BOOL bInReadOnly );
571 virtual int IsReplaceMode() const;
572 virtual ~SwFindParaText();
575 SwFindParaText::~SwFindParaText()
579 int SwFindParaText::Find( SwPaM* pCrsr, SwMoveFn fnMove,
580 const SwPaM* pRegion, BOOL bInReadOnly )
582 if( bInReadOnly && bReplace )
583 bInReadOnly = FALSE;
585 BOOL bFnd = (BOOL)pCrsr->Find( rSearchOpt, bSearchInNotes, aSTxt, fnMove, pRegion, bInReadOnly );
587 /* #i80135# if we found something in a note, Mark and Point is the same
588 if( bFnd && *pCrsr->GetMark() == *pCrsr->GetPoint() )
589 return FIND_NOT_FOUND;
592 if( bFnd && bReplace ) // String ersetzen ??
594 // Replace-Methode vom SwDoc benutzen
595 const bool bRegExp(SearchAlgorithms_REGEXP == rSearchOpt.algorithmType);
596 SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
597 xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
598 // damit die Region auch verschoben wird, in den Shell-Cursr-Ring
599 // mit aufnehmen !!
600 Ring *pPrev(0);
601 if( bRegExp )
603 pPrev = pRegion->GetPrev();
604 ((Ring*)pRegion)->MoveRingTo( &rCursor );
607 ::std::auto_ptr<String> pRepl( (bRegExp)
608 ? ReplaceBackReferences( rSearchOpt, pCrsr ) : 0 );
609 rCursor.GetDoc()->ReplaceRange( *pCrsr,
610 (pRepl.get()) ? *pRepl : String(rSearchOpt.replaceString),
611 bRegExp );
612 rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
614 if( bRegExp )
616 // und die Region wieder herausnehmen:
617 Ring *p, *pNext = (Ring*)pRegion;
618 do {
619 p = pNext;
620 pNext = p->GetNext();
621 p->MoveTo( (Ring*)pRegion );
622 } while( p != pPrev );
624 pCrsr->Start()->nContent = nSttCnt;
625 return FIND_NO_RING;
627 return bFnd ? FIND_FOUND : FIND_NOT_FOUND;
631 int SwFindParaText::IsReplaceMode() const
633 return bReplace;
637 ULONG SwCursor::Find( const SearchOptions& rSearchOpt, BOOL bSearchInNotes,
638 SwDocPositions nStart, SwDocPositions nEnde,
639 BOOL& bCancel,
640 FindRanges eFndRngs, int bReplace )
642 // OLE-Benachrichtigung abschalten !!
643 SwDoc* pDoc = GetDoc();
644 Link aLnk( pDoc->GetOle2Link() );
645 pDoc->SetOle2Link( Link() );
647 BOOL bSttUndo = pDoc->DoesUndo() && bReplace;
648 if( bSttUndo )
649 pDoc->StartUndo( UNDO_REPLACE, NULL );
651 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 ULONG nRet = FindAll( aSwFindParaText, nStart, nEnde, eFndRngs, bCancel );
656 pDoc->SetOle2Link( aLnk );
657 if( nRet && bReplace )
658 pDoc->SetModified();
660 if( bSttUndo )
661 pDoc->EndUndo( UNDO_REPLACE, NULL );
662 return nRet;
665 String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam )
667 String *pRet = 0;
668 if( pPam && pPam->HasMark() &&
669 SearchAlgorithms_REGEXP == rSearchOpt.algorithmType )
671 const SwCntntNode* pTxtNode = pPam->GetCntntNode( TRUE );
672 if( pTxtNode && pTxtNode->IsTxtNode() && pTxtNode == pPam->GetCntntNode( FALSE ) )
674 utl::TextSearch aSTxt( rSearchOpt );
675 String aStr( pPam->GetTxt() );
676 String aSearchStr( rSearchOpt.searchString );
677 String aReplaceStr( rSearchOpt.replaceString );
678 aStr.EraseAllChars( CH_TXTATR_BREAKWORD );
679 aStr.EraseAllChars( CH_TXTATR_INWORD );
680 xub_StrLen nStart = 0;
681 String sX( 'x' );
682 if( pPam->Start()->nContent > 0 )
684 aStr.Insert( sX, 0 );
685 ++nStart;
687 xub_StrLen nEnd = aStr.Len();
688 bool bDeleteLastX = false;
689 if( pPam->End()->nContent < (static_cast<const SwTxtNode*>(pTxtNode))->GetTxt().Len() )
691 aStr.Insert( sX );
692 bDeleteLastX = true;
694 SearchResult aResult;
695 if( aSTxt.SearchFrwrd( aStr, &nStart, &nEnd, &aResult ) )
697 if( bDeleteLastX )
698 aStr.Erase( aStr.Len() - 1 );
699 aSTxt.ReplaceBackReferences( aReplaceStr, aStr, aResult );
700 pRet = new String( aReplaceStr );
704 return pRet;