Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <com/sun/star/util/SearchOptions.hpp>
22 : #include <com/sun/star/util/SearchFlags.hpp>
23 :
24 : #include <comphelper/string.hxx>
25 :
26 : #include <vcl/svapp.hxx>
27 : #include <vcl/window.hxx>
28 :
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>
42 :
43 : #include <docsh.hxx>
44 : #include <PostItMgr.hxx>
45 : #include <viewsh.hxx>
46 :
47 : using namespace ::com::sun::star;
48 : using namespace util;
49 :
50 : String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam );
51 :
52 0 : static String& lcl_CleanStr( const SwTxtNode& rNd, xub_StrLen nStart, xub_StrLen& rEnd,
53 : std::vector<sal_uLong> &rArr, String& rRet,
54 : bool bRemoveSoftHyphen )
55 : {
56 0 : rRet = rNd.GetTxt();
57 0 : rArr.clear();
58 :
59 0 : const SwpHints *pHts = rNd.GetpSwpHints();
60 :
61 0 : sal_uInt16 n = 0;
62 0 : xub_StrLen nSoftHyphen = nStart;
63 0 : xub_StrLen nHintStart = STRING_LEN;
64 0 : bool bNewHint = true;
65 0 : bool bNewSoftHyphen = true;
66 0 : const xub_StrLen nEnd = rEnd;
67 0 : std::vector<sal_uInt16> aReplaced;
68 :
69 0 : do
70 : {
71 0 : if ( bNewHint )
72 0 : nHintStart = pHts && n < pHts->Count() ?
73 0 : *(*pHts)[n]->GetStart() :
74 0 : STRING_LEN;
75 :
76 0 : if ( bNewSoftHyphen )
77 : nSoftHyphen = bRemoveSoftHyphen ?
78 0 : rNd.GetTxt().Search( CHAR_SOFTHYPHEN, nSoftHyphen ) :
79 0 : STRING_LEN;
80 :
81 0 : bNewHint = false;
82 0 : bNewSoftHyphen = false;
83 :
84 0 : xub_StrLen nStt = 0;
85 :
86 : // Check if next stop is a hint.
87 0 : if ( STRING_LEN != nHintStart && nHintStart < nSoftHyphen && nHintStart < nEnd )
88 : {
89 0 : nStt = nHintStart;
90 0 : bNewHint = true;
91 : }
92 : // Check if next stop is a soft hyphen.
93 0 : else if ( STRING_LEN != nSoftHyphen && nSoftHyphen < nHintStart && nSoftHyphen < nEnd )
94 : {
95 0 : nStt = nSoftHyphen;
96 0 : bNewSoftHyphen = true;
97 : }
98 : // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end.
99 0 : else if ( STRING_LEN != nSoftHyphen && nSoftHyphen == nHintStart )
100 : {
101 0 : nStt = nSoftHyphen;
102 0 : bNewHint = true;
103 0 : bNewSoftHyphen = true;
104 : }
105 : else
106 : break;
107 :
108 0 : const xub_StrLen nAkt = nStt - rArr.size();
109 :
110 0 : if ( bNewHint )
111 : {
112 0 : const SwTxtAttr* pHt = (*pHts)[n];
113 0 : if ( pHt->HasDummyChar() && (nStt >= nStart) )
114 : {
115 0 : switch( pHt->Which() )
116 : {
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:
124 : {
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 0 : bool bEmpty = RES_TXTATR_FIELD != pHt->Which() ||
133 : !(static_cast<SwTxtFld const*>(pHt)
134 0 : ->GetFld().GetFld()->ExpandField(true).Len());
135 0 : if ( bEmpty && nStart == nAkt )
136 : {
137 0 : rArr.push_back( nAkt );
138 0 : --rEnd;
139 0 : rRet.Erase( nAkt, 1 );
140 : }
141 : else
142 : {
143 0 : if ( bEmpty )
144 0 : aReplaced.push_back( nAkt );
145 0 : rRet.SetChar( nAkt, '\x7f' );
146 : }
147 : }
148 0 : break;
149 : default:
150 : OSL_FAIL( "unknown case in lcl_CleanStr" );
151 0 : break;
152 : }
153 : }
154 0 : ++n;
155 : }
156 :
157 0 : if ( bNewSoftHyphen )
158 : {
159 0 : rArr.push_back( nAkt );
160 0 : --rEnd;
161 0 : rRet.Erase( nAkt, 1 );
162 0 : ++nSoftHyphen;
163 : }
164 : }
165 : while ( true );
166 :
167 0 : for( sal_uInt16 i = aReplaced.size(); i; )
168 : {
169 0 : const xub_StrLen nTmp = aReplaced[ --i ];
170 0 : if( nTmp == rRet.Len() - 1 )
171 : {
172 0 : rRet.Erase( nTmp );
173 0 : rArr.push_back( nTmp );
174 0 : --rEnd;
175 : }
176 : }
177 :
178 0 : return rRet;
179 : }
180 :
181 : // skip all non SwPostIts inside the array
182 0 : xub_StrLen GetPostIt(xub_StrLen aCount,const SwpHints *pHts)
183 : {
184 0 : xub_StrLen aIndex = 0;
185 0 : while (aCount)
186 : {
187 0 : for (xub_StrLen i = 0; i <pHts->Count();i++)
188 : {
189 0 : aIndex++;
190 0 : const SwTxtAttr* pTxtAttr = (*pHts)[i];
191 0 : if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
192 0 : (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
193 : {
194 0 : aCount--;
195 0 : if (!aCount)
196 0 : break;
197 : }
198 : }
199 : }
200 : // throw away all following non postits
201 0 : for (xub_StrLen i = aIndex; i <pHts->Count();i++)
202 : {
203 0 : const SwTxtAttr* pTxtAttr = (*pHts)[i];
204 0 : if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
205 0 : (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
206 0 : break;
207 : else
208 0 : aIndex++;
209 : }
210 0 : return aIndex;
211 : }
212 :
213 0 : sal_uInt8 SwPaM::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes , utl::TextSearch& rSTxt,
214 : SwMoveFn fnMove, const SwPaM * pRegion,
215 : sal_Bool bInReadOnly )
216 : {
217 0 : if( rSearchOpt.searchString.isEmpty() )
218 0 : return sal_False;
219 :
220 0 : SwPaM* pPam = MakeRegion( fnMove, pRegion );
221 0 : sal_Bool bSrchForward = fnMove == fnMoveForward;
222 0 : SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
223 0 : SwIndex& rCntntIdx = pPam->GetPoint()->nContent;
224 :
225 : // If a beginning/end, from out of node; stop if empty node
226 0 : if( bSrchForward
227 0 : ? ( rCntntIdx.GetIndex() == pPam->GetCntntNode()->Len() &&
228 0 : rCntntIdx.GetIndex() )
229 0 : : !rCntntIdx.GetIndex() && pPam->GetCntntNode()->Len() )
230 : {
231 0 : if( !(*fnMove->fnNds)( &rNdIdx, sal_False ))
232 : {
233 0 : delete pPam;
234 0 : return sal_False;
235 : }
236 0 : SwCntntNode *pNd = rNdIdx.GetNode().GetCntntNode();
237 0 : xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
238 0 : rCntntIdx.Assign( pNd, nTmpPos );
239 : }
240 :
241 : // If bFound is true then the string was found and is between nStart and nEnd
242 0 : sal_Bool bFound = sal_False;
243 : // start position in text or initial position
244 0 : sal_Bool bFirst = sal_True;
245 : SwCntntNode * pNode;
246 :
247 : xub_StrLen nStart, nEnd, nTxtLen;
248 :
249 0 : sal_Bool bRegSearch = SearchAlgorithms_REGEXP == rSearchOpt.algorithmType;
250 0 : sal_Bool bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() &&
251 0 : ( !rSearchOpt.searchString.compareToAscii( "^$" ) ||
252 0 : !rSearchOpt.searchString.compareToAscii( "$^" ) );
253 0 : sal_Bool bChkParaEnd = bRegSearch && 1 == rSearchOpt.searchString.getLength() &&
254 0 : !rSearchOpt.searchString.compareToAscii( "$" );
255 :
256 : // LanguageType eLastLang = 0;
257 0 : while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ))
258 : {
259 0 : if( pNode->IsTxtNode() )
260 : {
261 0 : nTxtLen = ((SwTxtNode*)pNode)->GetTxt().Len();
262 0 : if( rNdIdx == pPam->GetMark()->nNode )
263 0 : nEnd = pPam->GetMark()->nContent.GetIndex();
264 : else
265 0 : nEnd = bSrchForward ? nTxtLen : 0;
266 0 : nStart = rCntntIdx.GetIndex();
267 :
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 0 : const SwpHints *pHts = ((SwTxtNode*)pNode)->GetpSwpHints();
273 :
274 : // count PostItFields by looping over all fields
275 0 : xub_StrLen aNumberPostits = 0;
276 0 : xub_StrLen aIgnore = 0;
277 0 : if (pHts && bSearchInNotes)
278 : {
279 0 : if (!bSrchForward)
280 : {
281 0 : xub_StrLen swap = nEnd;
282 0 : nEnd = nStart;
283 0 : nStart = swap;
284 : }
285 :
286 0 : for (xub_StrLen i = 0; i <pHts->Count();i++)
287 : {
288 0 : xub_StrLen aPos = *(*pHts)[i]->GetStart();
289 0 : const SwTxtAttr* pTxtAttr = (*pHts)[i];
290 0 : if ( (pTxtAttr->Which()==RES_TXTATR_FIELD) &&
291 0 : (pTxtAttr->GetFld().GetFld()->Which()==RES_POSTITFLD))
292 : {
293 0 : if ( (aPos >= nStart) && (aPos <= nEnd) )
294 0 : aNumberPostits++;
295 : else
296 : {
297 0 : if (bSrchForward)
298 0 : aIgnore++;
299 : }
300 : }
301 : }
302 :
303 0 : if (!bSrchForward)
304 : {
305 0 : xub_StrLen swap = nEnd;
306 0 : nEnd = nStart;
307 0 : nStart = swap;
308 : }
309 :
310 : }
311 :
312 0 : SwDocShell *const pDocShell = pNode->GetDoc()->GetDocShell();
313 0 : ViewShell *const pWrtShell = (pDocShell) ? (ViewShell*)(pDocShell->GetWrtShell()) : 0;
314 0 : SwPostItMgr *const pPostItMgr = (pWrtShell) ? pWrtShell->GetPostItMgr() : 0;
315 :
316 0 : xub_StrLen aStart = 0;
317 : // do we need to finish a note?
318 0 : if (pPostItMgr && pPostItMgr->HasActiveSidebarWin())
319 : {
320 0 : if (bSearchInNotes)
321 : {
322 0 : if (bSrchForward)
323 0 : aStart++;
324 : else
325 : {
326 0 : if (aNumberPostits)
327 0 : --aNumberPostits;
328 : }
329 : //search inside and finsih and put focus back into the doc
330 0 : if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward))
331 : {
332 0 : bFound = true ;
333 0 : break;
334 : }
335 : }
336 : else
337 : {
338 0 : pPostItMgr->SetActiveSidebarWin(0);
339 : }
340 : }
341 :
342 0 : if (aNumberPostits)
343 : {
344 : // now we have to split
345 0 : xub_StrLen nStartInside = 0;
346 0 : xub_StrLen nEndInside = 0;
347 0 : sal_Int16 aLoop= bSrchForward ? aStart : aNumberPostits;
348 :
349 0 : while ( (aLoop>=0) && (aLoop<=aNumberPostits))
350 : {
351 0 : if (bSrchForward)
352 : {
353 0 : nStartInside = aLoop==0 ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
354 0 : nEndInside = aLoop==aNumberPostits ? nEnd : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
355 0 : nTxtLen = nEndInside - nStartInside;
356 : }
357 : else
358 : {
359 0 : nStartInside = aLoop==aNumberPostits ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
360 0 : nEndInside = aLoop==0 ? nEnd : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
361 0 : nTxtLen = nStartInside - nEndInside;
362 : }
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 0 : pPam );
368 0 : if ( bFound )
369 0 : break;
370 : else
371 : {
372 : // we should now be right in front of a note, search inside
373 0 : if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) ))
374 : {
375 0 : const SwTxtAttr* pTxtAttr = bSrchForward ? (*pHts)[GetPostIt(aLoop+aIgnore,pHts)] : (*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)];
376 0 : if ( pPostItMgr && pPostItMgr->SearchReplace(((SwTxtFld*)pTxtAttr)->GetFld(),rSearchOpt,bSrchForward) )
377 : {
378 0 : bFound = true ;
379 0 : break;
380 : }
381 : }
382 : }
383 0 : aLoop = bSrchForward ? aLoop+1 : aLoop-1;
384 : }
385 : }
386 : else
387 : {
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 0 : nStart, nEnd, nTxtLen, pNode, pPam );
393 : }
394 0 : if (bFound)
395 0 : break;
396 : }
397 : }
398 0 : delete pPam;
399 0 : return bFound;
400 : }
401 :
402 0 : 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)
407 : {
408 0 : bool bFound = false;
409 0 : SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
410 0 : const SwNode* pSttNd = &rNdIdx.GetNode();
411 0 : String sCleanStr;
412 0 : std::vector<sal_uLong> aFltArr;
413 0 : LanguageType eLastLang = 0;
414 : // if the search string contains a soft hypen,
415 : // we don't strip them from the text:
416 0 : bool bRemoveSoftHyphens = true;
417 0 : if ( bRegSearch )
418 : {
419 0 : const rtl::OUString a00AD(RTL_CONSTASCII_USTRINGPARAM("\\x00AD"));
420 0 : if ( -1 != rSearchOpt.searchString.indexOf( a00AD ) )
421 0 : bRemoveSoftHyphens = false;
422 : }
423 : else
424 : {
425 0 : if ( 1 == rSearchOpt.searchString.getLength() &&
426 0 : CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() )
427 0 : bRemoveSoftHyphens = false;
428 : }
429 :
430 0 : if( bSrchForward )
431 : lcl_CleanStr( *(SwTxtNode*)pNode, nStart, nEnd,
432 0 : aFltArr, sCleanStr, bRemoveSoftHyphens );
433 : else
434 : lcl_CleanStr( *(SwTxtNode*)pNode, nEnd, nStart,
435 0 : aFltArr, sCleanStr, bRemoveSoftHyphens );
436 :
437 0 : SwScriptIterator* pScriptIter = 0;
438 0 : sal_uInt16 nSearchScript = 0;
439 0 : sal_uInt16 nCurrScript = 0;
440 :
441 0 : if ( SearchAlgorithms_APPROXIMATE == rSearchOpt.algorithmType &&
442 0 : pBreakIt->GetBreakIter().is() )
443 : {
444 0 : pScriptIter = new SwScriptIterator( sCleanStr, nStart, bSrchForward );
445 0 : nSearchScript = pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 );
446 : }
447 :
448 0 : xub_StrLen nStringEnd = nEnd;
449 0 : while ( (bSrchForward && nStart < nStringEnd) ||
450 : (! bSrchForward && nStart > nStringEnd) )
451 : {
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 0 : if ( pScriptIter )
456 : {
457 0 : nEnd = pScriptIter->GetScriptChgPos();
458 0 : nCurrScript = pScriptIter->GetCurrScript();
459 0 : if ( nSearchScript == nCurrScript )
460 : {
461 : const LanguageType eCurrLang =
462 : ((SwTxtNode*)pNode)->GetLang( bSrchForward ?
463 : nStart :
464 0 : nEnd );
465 :
466 0 : if ( eCurrLang != eLastLang )
467 : {
468 : const lang::Locale aLocale(
469 0 : pBreakIt->GetLocale( eCurrLang ) );
470 0 : rSTxt.SetLocale( rSearchOpt, aLocale );
471 0 : eLastLang = eCurrLang;
472 : }
473 : }
474 0 : pScriptIter->Next();
475 : }
476 :
477 0 : if( nSearchScript == nCurrScript &&
478 0 : (rSTxt.*fnMove->fnSearch)( sCleanStr, &nStart, &nEnd, 0 ))
479 : {
480 : // set section correctly
481 0 : *GetPoint() = *pPam->GetPoint();
482 0 : SetMark();
483 :
484 : // adjust start and end
485 0 : if( !aFltArr.empty() )
486 : {
487 : xub_StrLen n, nNew;
488 : // if backward search, switch positions temporarily
489 0 : if( !bSrchForward ) { n = nStart; nStart = nEnd; nEnd = n; }
490 :
491 0 : for( n = 0, nNew = nStart;
492 0 : n < aFltArr.size() && aFltArr[ n ] <= nStart;
493 : ++n, ++nNew )
494 : ;
495 0 : nStart = nNew;
496 0 : for( n = 0, nNew = nEnd;
497 0 : n < aFltArr.size() && aFltArr[ n ] < nEnd;
498 : ++n, ++nNew )
499 : ;
500 :
501 0 : nEnd = nNew;
502 : // if backward search, switch positions temporarily
503 0 : if( !bSrchForward ) { n = nStart; nStart = nEnd; nEnd = n; }
504 : }
505 0 : GetMark()->nContent = nStart;
506 0 : GetPoint()->nContent = nEnd;
507 :
508 : // if backward search, switch point and mark
509 0 : if( !bSrchForward )
510 0 : Exchange();
511 0 : bFound = sal_True;
512 0 : break;
513 : }
514 0 : nStart = nEnd;
515 : }
516 :
517 0 : delete pScriptIter;
518 :
519 0 : if ( bFound )
520 0 : return true;
521 0 : else if( ( bChkEmptyPara && !nStart && !nTxtLen ) || bChkParaEnd )
522 : {
523 0 : *GetPoint() = *pPam->GetPoint();
524 0 : GetPoint()->nContent = bChkParaEnd ? nTxtLen : 0;
525 0 : SetMark();
526 0 : if( (bSrchForward || pSttNd != &rNdIdx.GetNode()) &&
527 0 : Move( fnMoveForward, fnGoCntnt ) &&
528 0 : (!bSrchForward || pSttNd != &GetPoint()->nNode.GetNode()) &&
529 0 : 1 == Abs( (int)( GetPoint()->nNode.GetIndex() -
530 0 : GetMark()->nNode.GetIndex()) ) )
531 : {
532 : // if backward search, switch point and mark
533 0 : if( !bSrchForward )
534 0 : Exchange();
535 0 : return true;
536 : }
537 : }
538 0 : return bFound;
539 : }
540 :
541 : /// parameters for search and replace in text
542 : struct SwFindParaText : public SwFindParas
543 : {
544 : const SearchOptions& rSearchOpt;
545 : SwCursor& rCursor;
546 : utl::TextSearch aSTxt;
547 : sal_Bool bReplace;
548 : sal_Bool bSearchInNotes;
549 :
550 0 : SwFindParaText( const SearchOptions& rOpt, sal_Bool bSearchNotes, int bRepl, SwCursor& rCrsr )
551 0 : : rSearchOpt( rOpt ), rCursor( rCrsr ), aSTxt( rOpt ), bReplace( 0 != bRepl ), bSearchInNotes( bSearchNotes )
552 0 : {}
553 : virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
554 : virtual int IsReplaceMode() const;
555 : virtual ~SwFindParaText();
556 : };
557 :
558 0 : SwFindParaText::~SwFindParaText()
559 : {
560 0 : }
561 :
562 0 : int SwFindParaText::Find( SwPaM* pCrsr, SwMoveFn fnMove,
563 : const SwPaM* pRegion, sal_Bool bInReadOnly )
564 : {
565 0 : if( bInReadOnly && bReplace )
566 0 : bInReadOnly = sal_False;
567 :
568 0 : sal_Bool bFnd = (sal_Bool)pCrsr->Find( rSearchOpt, bSearchInNotes, aSTxt, fnMove, pRegion, bInReadOnly );
569 :
570 :
571 0 : if( bFnd && bReplace ) // replace string
572 : {
573 : // use replace method in SwDoc
574 0 : const bool bRegExp(SearchAlgorithms_REGEXP == rSearchOpt.algorithmType);
575 0 : SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
576 0 : xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
577 : // add to shell-cursor-ring so that the regions will be moved enventually
578 0 : Ring *pPrev(0);
579 0 : if( bRegExp )
580 : {
581 0 : pPrev = pRegion->GetPrev();
582 0 : ((Ring*)pRegion)->MoveRingTo( &rCursor );
583 : }
584 :
585 : ::std::auto_ptr<String> pRepl( (bRegExp)
586 0 : ? ReplaceBackReferences( rSearchOpt, pCrsr ) : 0 );
587 0 : rCursor.GetDoc()->ReplaceRange( *pCrsr,
588 0 : (pRepl.get()) ? *pRepl : String(rSearchOpt.replaceString),
589 0 : bRegExp );
590 0 : rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
591 :
592 0 : if( bRegExp )
593 : {
594 : // and remove region again
595 0 : Ring *p, *pNext = (Ring*)pRegion;
596 0 : do {
597 0 : p = pNext;
598 0 : pNext = p->GetNext();
599 0 : p->MoveTo( (Ring*)pRegion );
600 : } while( p != pPrev );
601 : }
602 0 : pCrsr->Start()->nContent = nSttCnt;
603 0 : return FIND_NO_RING;
604 : }
605 0 : return bFnd ? FIND_FOUND : FIND_NOT_FOUND;
606 : }
607 :
608 :
609 0 : int SwFindParaText::IsReplaceMode() const
610 : {
611 0 : return bReplace;
612 : }
613 :
614 :
615 0 : sal_uLong SwCursor::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes,
616 : SwDocPositions nStart, SwDocPositions nEnd,
617 : sal_Bool& bCancel, FindRanges eFndRngs, int bReplace )
618 : {
619 : // switch off OLE-notifications
620 0 : SwDoc* pDoc = GetDoc();
621 0 : Link aLnk( pDoc->GetOle2Link() );
622 0 : pDoc->SetOle2Link( Link() );
623 :
624 0 : bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
625 0 : if (bStartUndo)
626 : {
627 0 : pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
628 : }
629 :
630 0 : bool bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE);
631 0 : if( bSearchSel )
632 0 : eFndRngs = (FindRanges)(eFndRngs | FND_IN_SEL);
633 0 : SwFindParaText aSwFindParaText( rSearchOpt, bSearchInNotes, bReplace, *this );
634 0 : sal_uLong nRet = FindAll( aSwFindParaText, nStart, nEnd, eFndRngs, bCancel );
635 0 : pDoc->SetOle2Link( aLnk );
636 0 : if( nRet && bReplace )
637 0 : pDoc->SetModified();
638 :
639 0 : if (bStartUndo)
640 : {
641 : SwRewriter rewriter(MakeUndoReplaceRewriter(
642 0 : nRet, rSearchOpt.searchString, rSearchOpt.replaceString));
643 0 : pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, & rewriter );
644 : }
645 0 : return nRet;
646 : }
647 :
648 0 : String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam )
649 : {
650 0 : String *pRet = 0;
651 0 : if( pPam && pPam->HasMark() &&
652 : SearchAlgorithms_REGEXP == rSearchOpt.algorithmType )
653 : {
654 0 : const SwCntntNode* pTxtNode = pPam->GetCntntNode( sal_True );
655 0 : if( pTxtNode && pTxtNode->IsTxtNode() && pTxtNode == pPam->GetCntntNode( sal_False ) )
656 : {
657 0 : utl::TextSearch aSTxt( rSearchOpt );
658 0 : String aStr( pPam->GetTxt() );
659 0 : String aReplaceStr( rSearchOpt.replaceString );
660 0 : aStr = comphelper::string::remove(aStr, CH_TXTATR_BREAKWORD);
661 0 : aStr = comphelper::string::remove(aStr, CH_TXTATR_INWORD);
662 0 : xub_StrLen nStart = 0;
663 0 : rtl::OUString sX( 'x' );
664 0 : if( pPam->Start()->nContent > 0 )
665 : {
666 0 : aStr.Insert( sX, 0 );
667 0 : ++nStart;
668 : }
669 0 : xub_StrLen nEnd = aStr.Len();
670 0 : bool bDeleteLastX = false;
671 0 : if( pPam->End()->nContent < (static_cast<const SwTxtNode*>(pTxtNode))->GetTxt().Len() )
672 : {
673 0 : aStr.Insert( sX );
674 0 : bDeleteLastX = true;
675 : }
676 0 : SearchResult aResult;
677 0 : if( aSTxt.SearchFrwrd( aStr, &nStart, &nEnd, &aResult ) )
678 : {
679 0 : if( bDeleteLastX )
680 0 : aStr.Erase( aStr.Len() - 1 );
681 0 : aSTxt.ReplaceBackReferences( aReplaceStr, aStr, aResult );
682 0 : pRet = new String( aReplaceStr );
683 0 : }
684 : }
685 : }
686 0 : return pRet;
687 : }
688 :
689 :
690 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|