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