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