Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / crsr / findtxt.cxx
blobc1231f9f06307db8ea8b1c7597b5e008f9c592cc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/util/SearchOptions.hpp>
22 #include <com/sun/star/util/SearchFlags.hpp>
24 #include <comphelper/string.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/window.hxx>
29 #include <txatritr.hxx>
30 #include <fldbas.hxx>
31 #include <fmtfld.hxx>
32 #include <txtatr.hxx>
33 #include <txtfld.hxx>
34 #include <swcrsr.hxx>
35 #include <doc.hxx>
36 #include <IDocumentUndoRedo.hxx>
37 #include <pamtyp.hxx>
38 #include <ndtxt.hxx>
39 #include <swundo.hxx>
40 #include <UndoInsert.hxx>
41 #include <breakit.hxx>
43 #include <docsh.hxx>
44 #include <PostItMgr.hxx>
45 #include <viewsh.hxx>
47 using namespace ::com::sun::star;
48 using namespace util;
50 String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam );
52 static String& lcl_CleanStr( const SwTxtNode& rNd, xub_StrLen nStart, xub_StrLen& rEnd,
53 std::vector<sal_uLong> &rArr, String& rRet,
54 bool bRemoveSoftHyphen )
56 rRet = rNd.GetTxt();
57 rArr.clear();
59 const SwpHints *pHts = rNd.GetpSwpHints();
61 sal_uInt16 n = 0;
62 xub_StrLen nSoftHyphen = nStart;
63 xub_StrLen nHintStart = STRING_LEN;
64 bool bNewHint = true;
65 bool bNewSoftHyphen = true;
66 const xub_StrLen nEnd = rEnd;
67 std::vector<sal_uInt16> aReplaced;
71 if ( bNewHint )
72 nHintStart = pHts && n < pHts->Count() ?
73 *(*pHts)[n]->GetStart() :
74 STRING_LEN;
76 if ( bNewSoftHyphen )
77 nSoftHyphen = bRemoveSoftHyphen ?
78 rNd.GetTxt().Search( CHAR_SOFTHYPHEN, nSoftHyphen ) :
79 STRING_LEN;
81 bNewHint = false;
82 bNewSoftHyphen = false;
84 xub_StrLen nStt = 0;
86 // Check if next stop is a hint.
87 if ( STRING_LEN != nHintStart && nHintStart < nSoftHyphen && nHintStart < nEnd )
89 nStt = nHintStart;
90 bNewHint = true;
92 // Check if next stop is a soft hyphen.
93 else if ( STRING_LEN != nSoftHyphen && nSoftHyphen < nHintStart && nSoftHyphen < nEnd )
95 nStt = nSoftHyphen;
96 bNewSoftHyphen = true;
98 // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end.
99 else if ( STRING_LEN != nSoftHyphen && nSoftHyphen == nHintStart )
101 nStt = nSoftHyphen;
102 bNewHint = true;
103 bNewSoftHyphen = true;
105 else
106 break;
108 const xub_StrLen nAkt = nStt - rArr.size();
110 if ( bNewHint )
112 const SwTxtAttr* pHt = (*pHts)[n];
113 if ( pHt->HasDummyChar() && (nStt >= nStart) )
115 switch( pHt->Which() )
117 case RES_TXTATR_FLYCNT:
118 case RES_TXTATR_FTN:
119 case RES_TXTATR_FIELD:
120 case RES_TXTATR_REFMARK:
121 case RES_TXTATR_TOXMARK:
122 case RES_TXTATR_META:
123 case RES_TXTATR_METAFIELD:
125 // (1998) they are desired as separators and
126 // belong not any longer to a word.
127 // they should also be ignored at a
128 // beginning/end of a sentence if blank. Those are
129 // simply removed if first. If at the end, we keep the
130 // replacement and remove afterwards all at a string's
131 // end (might be normal 0x7f).
132 bool bEmpty = RES_TXTATR_FIELD != pHt->Which() ||
133 !(static_cast<SwTxtFld const*>(pHt)
134 ->GetFld().GetFld()->ExpandField(true).Len());
135 if ( bEmpty && nStart == nAkt )
137 rArr.push_back( nAkt );
138 --rEnd;
139 rRet.Erase( nAkt, 1 );
141 else
143 if ( bEmpty )
144 aReplaced.push_back( nAkt );
145 rRet.SetChar( nAkt, '\x7f' );
148 break;
149 default:
150 OSL_FAIL( "unknown case in lcl_CleanStr" );
151 break;
154 ++n;
157 if ( bNewSoftHyphen )
159 rArr.push_back( nAkt );
160 --rEnd;
161 rRet.Erase( nAkt, 1 );
162 ++nSoftHyphen;
165 while ( true );
167 for( sal_uInt16 i = aReplaced.size(); i; )
169 const xub_StrLen nTmp = aReplaced[ --i ];
170 if( nTmp == rRet.Len() - 1 )
172 rRet.Erase( nTmp );
173 rArr.push_back( nTmp );
174 --rEnd;
178 return rRet;
181 // skip all non SwPostIts inside the array
182 xub_StrLen GetPostIt(xub_StrLen aCount,const SwpHints *pHts)
184 xub_StrLen aIndex = 0;
185 while (aCount)
187 for (xub_StrLen i = 0; i <pHts->Count();i++)
189 aIndex++;
190 const SwTxtAttr* pTxtAttr = (*pHts)[i];
191 if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
192 (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
194 aCount--;
195 if (!aCount)
196 break;
200 // throw away all following non postits
201 for (xub_StrLen i = aIndex; i <pHts->Count();i++)
203 const SwTxtAttr* pTxtAttr = (*pHts)[i];
204 if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
205 (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
206 break;
207 else
208 aIndex++;
210 return aIndex;
213 sal_uInt8 SwPaM::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes , utl::TextSearch& rSTxt,
214 SwMoveFn fnMove, const SwPaM * pRegion,
215 sal_Bool bInReadOnly )
217 if( rSearchOpt.searchString.isEmpty() )
218 return sal_False;
220 SwPaM* pPam = MakeRegion( fnMove, pRegion );
221 sal_Bool bSrchForward = fnMove == fnMoveForward;
222 SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
223 SwIndex& rCntntIdx = pPam->GetPoint()->nContent;
225 // If a beginning/end, from out of node; stop if empty node
226 if( bSrchForward
227 ? ( rCntntIdx.GetIndex() == pPam->GetCntntNode()->Len() &&
228 rCntntIdx.GetIndex() )
229 : !rCntntIdx.GetIndex() && pPam->GetCntntNode()->Len() )
231 if( !(*fnMove->fnNds)( &rNdIdx, sal_False ))
233 delete pPam;
234 return sal_False;
236 SwCntntNode *pNd = rNdIdx.GetNode().GetCntntNode();
237 xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
238 rCntntIdx.Assign( pNd, nTmpPos );
241 // If bFound is true then the string was found and is between nStart and nEnd
242 sal_Bool bFound = sal_False;
243 // start position in text or initial position
244 sal_Bool bFirst = sal_True;
245 SwCntntNode * pNode;
247 xub_StrLen nStart, nEnd, nTxtLen;
249 sal_Bool bRegSearch = SearchAlgorithms_REGEXP == rSearchOpt.algorithmType;
250 sal_Bool bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() &&
251 ( !rSearchOpt.searchString.compareToAscii( "^$" ) ||
252 !rSearchOpt.searchString.compareToAscii( "$^" ) );
253 sal_Bool bChkParaEnd = bRegSearch && 1 == rSearchOpt.searchString.getLength() &&
254 !rSearchOpt.searchString.compareToAscii( "$" );
256 // LanguageType eLastLang = 0;
257 while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ))
259 if( pNode->IsTxtNode() )
261 nTxtLen = ((SwTxtNode*)pNode)->GetTxt().Len();
262 if( rNdIdx == pPam->GetMark()->nNode )
263 nEnd = pPam->GetMark()->nContent.GetIndex();
264 else
265 nEnd = bSrchForward ? nTxtLen : 0;
266 nStart = rCntntIdx.GetIndex();
268 /* #i80135# */
269 // if there are SwPostItFields inside our current node text, we
270 // split the text into seperate pieces and search for text inside
271 // the pieces as well as inside the fields
272 const SwpHints *pHts = ((SwTxtNode*)pNode)->GetpSwpHints();
274 // count PostItFields by looping over all fields
275 xub_StrLen aNumberPostits = 0;
276 xub_StrLen aIgnore = 0;
277 if (pHts && bSearchInNotes)
279 if (!bSrchForward)
281 xub_StrLen swap = nEnd;
282 nEnd = nStart;
283 nStart = swap;
286 for (xub_StrLen i = 0; i <pHts->Count();i++)
288 xub_StrLen aPos = *(*pHts)[i]->GetStart();
289 const SwTxtAttr* pTxtAttr = (*pHts)[i];
290 if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
291 (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
293 if ( (aPos >= nStart) && (aPos <= nEnd) )
294 aNumberPostits++;
295 else
297 if (bSrchForward)
298 aIgnore++;
303 if (!bSrchForward)
305 xub_StrLen swap = nEnd;
306 nEnd = nStart;
307 nStart = swap;
312 SwDocShell *const pDocShell = pNode->GetDoc()->GetDocShell();
313 ViewShell *const pWrtShell = (pDocShell) ? (ViewShell*)(pDocShell->GetWrtShell()) : 0;
314 SwPostItMgr *const pPostItMgr = (pWrtShell) ? pWrtShell->GetPostItMgr() : 0;
316 xub_StrLen aStart = 0;
317 // do we need to finish a note?
318 if (pPostItMgr && pPostItMgr->HasActiveSidebarWin())
320 if (bSearchInNotes)
322 if (bSrchForward)
323 aStart++;
324 else
326 if (aNumberPostits)
327 --aNumberPostits;
329 //search inside and finsih and put focus back into the doc
330 if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward))
332 bFound = true ;
333 break;
336 else
338 pPostItMgr->SetActiveSidebarWin(0);
342 if (aNumberPostits)
344 // now we have to split
345 xub_StrLen nStartInside = 0;
346 xub_StrLen nEndInside = 0;
347 sal_Int16 aLoop= bSrchForward ? aStart : aNumberPostits;
349 while ( (aLoop>=0) && (aLoop<=aNumberPostits))
351 if (bSrchForward)
353 nStartInside = aLoop==0 ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
354 nEndInside = aLoop==aNumberPostits ? nEnd : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
355 nTxtLen = nEndInside - nStartInside;
357 else
359 nStartInside = aLoop==aNumberPostits ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
360 nEndInside = aLoop==0 ? nEnd : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
361 nTxtLen = nStartInside - nEndInside;
363 // search inside the text between a note
364 bFound = DoSearch( rSearchOpt, rSTxt, fnMove, bSrchForward,
365 bRegSearch, bChkEmptyPara, bChkParaEnd,
366 nStartInside, nEndInside, nTxtLen, pNode,
367 pPam );
368 if ( bFound )
369 break;
370 else
372 // we should now be right in front of a note, search inside
373 if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) ))
375 const SwTxtAttr* pTxtAttr = bSrchForward ? (*pHts)[GetPostIt(aLoop+aIgnore,pHts)] : (*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)];
376 if ( pPostItMgr && pPostItMgr->SearchReplace(((SwTxtFld*)pTxtAttr)->GetFld(),rSearchOpt,bSrchForward) )
378 bFound = true ;
379 break;
383 aLoop = bSrchForward ? aLoop+1 : aLoop-1;
386 else
388 // if there is no SwPostItField inside or searching inside notes
389 // is disabled, we search the whole length just like before
390 bFound = DoSearch( rSearchOpt, rSTxt, fnMove, bSrchForward,
391 bRegSearch, bChkEmptyPara, bChkParaEnd,
392 nStart, nEnd, nTxtLen, pNode, pPam );
394 if (bFound)
395 break;
398 delete pPam;
399 return bFound;
402 bool SwPaM::DoSearch( const SearchOptions& rSearchOpt, utl::TextSearch& rSTxt,
403 SwMoveFn fnMove, sal_Bool bSrchForward, sal_Bool bRegSearch,
404 sal_Bool bChkEmptyPara, sal_Bool bChkParaEnd,
405 xub_StrLen &nStart, xub_StrLen &nEnd, xub_StrLen nTxtLen,
406 SwNode* pNode, SwPaM* pPam)
408 bool bFound = false;
409 SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
410 const SwNode* pSttNd = &rNdIdx.GetNode();
411 String sCleanStr;
412 std::vector<sal_uLong> aFltArr;
413 LanguageType eLastLang = 0;
414 // if the search string contains a soft hypen,
415 // we don't strip them from the text:
416 bool bRemoveSoftHyphens = true;
417 if ( bRegSearch )
419 const rtl::OUString a00AD(RTL_CONSTASCII_USTRINGPARAM("\\x00AD"));
420 if ( -1 != rSearchOpt.searchString.indexOf( a00AD ) )
421 bRemoveSoftHyphens = false;
423 else
425 if ( 1 == rSearchOpt.searchString.getLength() &&
426 CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() )
427 bRemoveSoftHyphens = false;
430 if( bSrchForward )
431 lcl_CleanStr( *(SwTxtNode*)pNode, nStart, nEnd,
432 aFltArr, sCleanStr, bRemoveSoftHyphens );
433 else
434 lcl_CleanStr( *(SwTxtNode*)pNode, nEnd, nStart,
435 aFltArr, sCleanStr, bRemoveSoftHyphens );
437 SwScriptIterator* pScriptIter = 0;
438 sal_uInt16 nSearchScript = 0;
439 sal_uInt16 nCurrScript = 0;
441 if ( SearchAlgorithms_APPROXIMATE == rSearchOpt.algorithmType &&
442 pBreakIt->GetBreakIter().is() )
444 pScriptIter = new SwScriptIterator( sCleanStr, nStart, bSrchForward );
445 nSearchScript = pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 );
448 xub_StrLen nStringEnd = nEnd;
449 while ( (bSrchForward && nStart < nStringEnd) ||
450 (! bSrchForward && nStart > nStringEnd) )
452 // SearchAlgorithms_APPROXIMATE works on a per word base so we have to
453 // provide the text searcher with the correct locale, because it uses
454 // the break-iterator
455 if ( pScriptIter )
457 nEnd = pScriptIter->GetScriptChgPos();
458 nCurrScript = pScriptIter->GetCurrScript();
459 if ( nSearchScript == nCurrScript )
461 const LanguageType eCurrLang =
462 ((SwTxtNode*)pNode)->GetLang( bSrchForward ?
463 nStart :
464 nEnd );
466 if ( eCurrLang != eLastLang )
468 const lang::Locale aLocale(
469 pBreakIt->GetLocale( eCurrLang ) );
470 rSTxt.SetLocale( rSearchOpt, aLocale );
471 eLastLang = eCurrLang;
474 pScriptIter->Next();
477 if( nSearchScript == nCurrScript &&
478 (rSTxt.*fnMove->fnSearch)( sCleanStr, &nStart, &nEnd, 0 ))
480 // set section correctly
481 *GetPoint() = *pPam->GetPoint();
482 SetMark();
484 // adjust start and end
485 if( !aFltArr.empty() )
487 xub_StrLen n, nNew;
488 // if backward search, switch positions temporarily
489 if( !bSrchForward ) { n = nStart; nStart = nEnd; nEnd = n; }
491 for( n = 0, nNew = nStart;
492 n < aFltArr.size() && aFltArr[ n ] <= nStart;
493 ++n, ++nNew )
495 nStart = nNew;
496 for( n = 0, nNew = nEnd;
497 n < aFltArr.size() && aFltArr[ n ] < nEnd;
498 ++n, ++nNew )
501 nEnd = nNew;
502 // if backward search, switch positions temporarily
503 if( !bSrchForward ) { n = nStart; nStart = nEnd; nEnd = n; }
505 GetMark()->nContent = nStart;
506 GetPoint()->nContent = nEnd;
508 // if backward search, switch point and mark
509 if( !bSrchForward )
510 Exchange();
511 bFound = sal_True;
512 break;
514 nStart = nEnd;
517 delete pScriptIter;
519 if ( bFound )
520 return true;
521 else if( ( bChkEmptyPara && !nStart && !nTxtLen ) || bChkParaEnd )
523 *GetPoint() = *pPam->GetPoint();
524 GetPoint()->nContent = bChkParaEnd ? nTxtLen : 0;
525 SetMark();
526 if( (bSrchForward || pSttNd != &rNdIdx.GetNode()) &&
527 Move( fnMoveForward, fnGoCntnt ) &&
528 (!bSrchForward || pSttNd != &GetPoint()->nNode.GetNode()) &&
529 1 == Abs( (int)( GetPoint()->nNode.GetIndex() -
530 GetMark()->nNode.GetIndex()) ) )
532 // if backward search, switch point and mark
533 if( !bSrchForward )
534 Exchange();
535 return true;
538 return bFound;
541 /// parameters for search and replace in text
542 struct SwFindParaText : public SwFindParas
544 const SearchOptions& rSearchOpt;
545 SwCursor& rCursor;
546 utl::TextSearch aSTxt;
547 sal_Bool bReplace;
548 sal_Bool bSearchInNotes;
550 SwFindParaText( const SearchOptions& rOpt, sal_Bool bSearchNotes, int bRepl, SwCursor& rCrsr )
551 : rSearchOpt( rOpt ), rCursor( rCrsr ), aSTxt( rOpt ), bReplace( 0 != bRepl ), bSearchInNotes( bSearchNotes )
553 virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
554 virtual int IsReplaceMode() const;
555 virtual ~SwFindParaText();
558 SwFindParaText::~SwFindParaText()
562 int SwFindParaText::Find( SwPaM* pCrsr, SwMoveFn fnMove,
563 const SwPaM* pRegion, sal_Bool bInReadOnly )
565 if( bInReadOnly && bReplace )
566 bInReadOnly = sal_False;
568 sal_Bool bFnd = (sal_Bool)pCrsr->Find( rSearchOpt, bSearchInNotes, aSTxt, fnMove, pRegion, bInReadOnly );
571 if( bFnd && bReplace ) // replace string
573 // use replace method in SwDoc
574 const bool bRegExp(SearchAlgorithms_REGEXP == rSearchOpt.algorithmType);
575 SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
576 xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
577 // add to shell-cursor-ring so that the regions will be moved enventually
578 Ring *pPrev(0);
579 if( bRegExp )
581 pPrev = pRegion->GetPrev();
582 ((Ring*)pRegion)->MoveRingTo( &rCursor );
585 ::std::auto_ptr<String> pRepl( (bRegExp)
586 ? ReplaceBackReferences( rSearchOpt, pCrsr ) : 0 );
587 rCursor.GetDoc()->ReplaceRange( *pCrsr,
588 (pRepl.get()) ? *pRepl : String(rSearchOpt.replaceString),
589 bRegExp );
590 rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
592 if( bRegExp )
594 // and remove region again
595 Ring *p, *pNext = (Ring*)pRegion;
596 do {
597 p = pNext;
598 pNext = p->GetNext();
599 p->MoveTo( (Ring*)pRegion );
600 } while( p != pPrev );
602 pCrsr->Start()->nContent = nSttCnt;
603 return FIND_NO_RING;
605 return bFnd ? FIND_FOUND : FIND_NOT_FOUND;
609 int SwFindParaText::IsReplaceMode() const
611 return bReplace;
615 sal_uLong SwCursor::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes,
616 SwDocPositions nStart, SwDocPositions nEnd,
617 sal_Bool& bCancel, FindRanges eFndRngs, int bReplace )
619 // switch off OLE-notifications
620 SwDoc* pDoc = GetDoc();
621 Link aLnk( pDoc->GetOle2Link() );
622 pDoc->SetOle2Link( Link() );
624 bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
625 if (bStartUndo)
627 pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
630 bool bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE);
631 if( bSearchSel )
632 eFndRngs = (FindRanges)(eFndRngs | FND_IN_SEL);
633 SwFindParaText aSwFindParaText( rSearchOpt, bSearchInNotes, bReplace, *this );
634 sal_uLong nRet = FindAll( aSwFindParaText, nStart, nEnd, eFndRngs, bCancel );
635 pDoc->SetOle2Link( aLnk );
636 if( nRet && bReplace )
637 pDoc->SetModified();
639 if (bStartUndo)
641 SwRewriter rewriter(MakeUndoReplaceRewriter(
642 nRet, rSearchOpt.searchString, rSearchOpt.replaceString));
643 pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, & rewriter );
645 return nRet;
648 String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam )
650 String *pRet = 0;
651 if( pPam && pPam->HasMark() &&
652 SearchAlgorithms_REGEXP == rSearchOpt.algorithmType )
654 const SwCntntNode* pTxtNode = pPam->GetCntntNode( sal_True );
655 if( pTxtNode && pTxtNode->IsTxtNode() && pTxtNode == pPam->GetCntntNode( sal_False ) )
657 utl::TextSearch aSTxt( rSearchOpt );
658 String aStr( pPam->GetTxt() );
659 String aReplaceStr( rSearchOpt.replaceString );
660 aStr = comphelper::string::remove(aStr, CH_TXTATR_BREAKWORD);
661 aStr = comphelper::string::remove(aStr, CH_TXTATR_INWORD);
662 xub_StrLen nStart = 0;
663 rtl::OUString sX( 'x' );
664 if( pPam->Start()->nContent > 0 )
666 aStr.Insert( sX, 0 );
667 ++nStart;
669 xub_StrLen nEnd = aStr.Len();
670 bool bDeleteLastX = false;
671 if( pPam->End()->nContent < (static_cast<const SwTxtNode*>(pTxtNode))->GetTxt().Len() )
673 aStr.Insert( sX );
674 bDeleteLastX = true;
676 SearchResult aResult;
677 if( aSTxt.SearchFrwrd( aStr, &nStart, &nEnd, &aResult ) )
679 if( bDeleteLastX )
680 aStr.Erase( aStr.Len() - 1 );
681 aSTxt.ReplaceBackReferences( aReplaceStr, aStr, aResult );
682 pRet = new String( aReplaceStr );
686 return pRet;
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */