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