LibreOffice Module sw (master)  1
viewsrch.cxx
Go to the documentation of this file.
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 <config_features.h>
21 
22 #include <string>
23 
24 #include <memory>
25 #include <boost/property_tree/json_parser.hpp>
26 
27 #include <hintids.hxx>
28 
29 #include <sal/log.hxx>
30 #include <svl/cjkoptions.hxx>
31 #include <svl/ctloptions.hxx>
32 #include <svx/pageitem.hxx>
33 #include <svl/whiter.hxx>
34 #include <sfx2/dispatch.hxx>
35 #include <sfx2/viewfrm.hxx>
36 #include <svl/stritem.hxx>
37 #include <unotools/textsearch.hxx>
38 #include <svl/itempool.hxx>
39 #include <svl/eitem.hxx>
40 #include <svl/srchitem.hxx>
41 #include <sal/macros.h>
42 #include <sfx2/request.hxx>
43 #include <svx/srchdlg.hxx>
44 #include <svx/dialogs.hrc>
45 #include <svx/svxids.hrc>
46 #include <editeng/unolingu.hxx>
47 #include <edtwin.hxx>
48 #include <swmodule.hxx>
49 #include <swwait.hxx>
50 #include <workctrl.hxx>
51 #include <view.hxx>
52 #include <wrtsh.hxx>
53 #include <swundo.hxx>
54 #include <uitool.hxx>
55 #include <cmdid.h>
56 #include <docsh.hxx>
57 #include <doc.hxx>
58 #include <unocrsr.hxx>
59 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
60 #include <comphelper/lok.hxx>
61 #include <comphelper/string.hxx>
62 
63 #include <strings.hrc>
64 #include <SwRewriter.hxx>
66 #include <drawdoc.hxx>
67 
68 #include <PostItMgr.hxx>
69 
70 using namespace com::sun::star;
71 using namespace ::com::sun::star::i18n;
72 using namespace ::com::sun::star::lang;
73 using namespace ::com::sun::star::util;
74 
75 //Search Parameter
76 
78 {
80  bool bDontWrap;
81 
82  SwSearchOptions( SwWrtShell const * pSh, bool bBackward );
83 };
84 
86 static void lcl_addContainerToJson(boost::property_tree::ptree& rTree, const OString& rKey, const std::vector<OString>& rMatches)
87 {
88  boost::property_tree::ptree aChildren;
89 
90  for (const OString& rMatch : rMatches)
91  {
92  boost::property_tree::ptree aChild;
93  aChild.put("part", "0");
94  aChild.put("rectangles", rMatch.getStr());
95  aChildren.push_back(std::make_pair("", aChild));
96  }
97 
98  rTree.add_child(rKey.getStr(), aChildren);
99 }
100 
102 static void lcl_emitSearchResultCallbacks(SvxSearchItem const * pSearchItem, SwWrtShell const * pWrtShell, bool bHighlightAll)
103 {
104  // Emit a callback also about the selection rectangles, grouped by matches.
105  if (SwPaM* pPaM = pWrtShell->GetCursor())
106  {
107  std::vector<OString> aMatches;
108  for (SwPaM& rPaM : pPaM->GetRingContainer())
109  {
110  if (SwShellCursor* pShellCursor = dynamic_cast<SwShellCursor*>(&rPaM))
111  {
112  std::vector<OString> aSelectionRectangles;
113  pShellCursor->SwSelPaintRects::Show(&aSelectionRectangles);
114  std::vector<OString> aRect;
115  for (const OString & rSelectionRectangle : aSelectionRectangles)
116  {
117  if (rSelectionRectangle.isEmpty())
118  continue;
119  aRect.push_back(rSelectionRectangle);
120  }
121  OString sRect = comphelper::string::join("; ", aRect);
122  aMatches.push_back(sRect);
123  }
124  }
125  boost::property_tree::ptree aTree;
126  aTree.put("searchString", pSearchItem->GetSearchString().toUtf8().getStr());
127  aTree.put("highlightAll", bHighlightAll);
128  lcl_addContainerToJson(aTree, "searchResultSelection", aMatches);
129 
130  std::stringstream aStream;
131  boost::property_tree::write_json(aStream, aTree);
132  OString aPayload = aStream.str().c_str();
133 
134  pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload.getStr());
135  }
136 }
137 
139 {
140  const SfxItemSet* pArgs = rReq.GetArgs();
141  const SfxPoolItem* pItem = nullptr;
142  bool bQuiet = false;
143  if(pArgs && SfxItemState::SET == pArgs->GetItemState(SID_SEARCH_QUIET, false, &pItem))
144  bQuiet = static_cast<const SfxBoolItem*>( pItem)->GetValue();
145 
146  sal_uInt16 nSlot = rReq.GetSlot();
147  if (nSlot == FN_REPEAT_SEARCH && !s_pSrchItem)
148  {
149  if(bQuiet)
150  {
151  rReq.SetReturnValue(SfxBoolItem(nSlot, false));
152  nSlot = 0;
153  }
154  }
155  if( m_pWrtShell->IsBlockMode() )
156  m_pWrtShell->LeaveBlockMode();
157  switch (nSlot)
158  {
159  // for now do nothing
160  case SID_SEARCH_ITEM:
161  {
162  delete s_pSrchItem;
163  s_pSrchItem = static_cast<SvxSearchItem*>( pArgs->Get(SID_SEARCH_ITEM).Clone() );
164  }
165  break;
166 
167  case FID_SEARCH_ON:
168  s_bJustOpened = true;
169  GetViewFrame()->GetBindings().Invalidate(SID_SEARCH_ITEM);
170  break;
171 
172  case FID_SEARCH_OFF:
173  if(pArgs)
174  {
175  // Unregister dialog
176  delete s_pSrchItem;
177  s_pSrchItem = static_cast<SvxSearchItem*>( pArgs->Get(SID_SEARCH_ITEM).Clone() );
178 
179  DELETEZ( s_pSearchList );
180  DELETEZ( s_pReplaceList );
181 
182  SvxSearchDialog *const pSrchDlg(GetSearchDialog());
183  if (pSrchDlg)
184  {
185  // We will remember the search-/replace items.
186  const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList();
187  if( nullptr != pList && pList->Count() )
188  s_pSearchList = new SearchAttrItemList( *pList );
189 
190  pList = pSrchDlg->GetReplaceItemList();
191  if (nullptr != pList && pList->Count())
192  s_pReplaceList = new SearchAttrItemList( *pList );
193  }
194  }
195  break;
196 
197  case FN_REPEAT_SEARCH:
198  case FID_SEARCH_NOW:
199  {
200  sal_uInt16 nMoveType = SwView::GetMoveType();
201  {
202  if(FID_SEARCH_NOW == nSlot && !rReq.IsAPI())
204  }
205 
206  SvxSearchDialog * pSrchDlg(GetSearchDialog());
207  if (pSrchDlg)
208  {
209  DELETEZ( s_pSearchList );
210  DELETEZ( s_pReplaceList );
211 
212  const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList();
213  if( nullptr != pList && pList->Count() )
214  s_pSearchList = new SearchAttrItemList( *pList );
215 
216  pList = pSrchDlg->GetReplaceItemList();
217  if (nullptr != pList && pList->Count())
218  s_pReplaceList = new SearchAttrItemList( *pList );
219  }
220 
221  if (nSlot == FN_REPEAT_SEARCH)
222  {
223  OSL_ENSURE(s_pSrchItem, "SearchItem missing");
224  if( !s_pSrchItem )
225  s_pSrchItem = new SvxSearchItem(SID_SEARCH_ITEM);
226  }
227  else
228  {
229  // Get SearchItem from request
230  OSL_ENSURE(pArgs, "Args missing");
231  if ( pArgs )
232  {
233  delete s_pSrchItem;
234  s_pSrchItem = static_cast<SvxSearchItem*>( pArgs->Get(SID_SEARCH_ITEM).Clone() );
235  }
236  }
237  SvxSearchCmd eCommand = s_pSrchItem->GetCommand();
238  switch (eCommand)
239  {
240  case SvxSearchCmd::FIND:
241  {
242  bool bRet = SearchAndWrap(bQuiet);
243  if( bRet )
244  {
245  Scroll(m_pWrtShell->GetCharRect().SVRect());
247  lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ false);
248  }
249  rReq.SetReturnValue(SfxBoolItem(nSlot, bRet));
250 #if HAVE_FEATURE_DESKTOP
251  {
252  pSrchDlg = GetSearchDialog();
253  if (pSrchDlg)
254  {
255  pSrchDlg->SetDocWin(m_pEditWin, eCommand);
256  pSrchDlg->SetSrchFlag(false);
257  }
258  }
259 #endif
260  }
261  break;
262  case SvxSearchCmd::FIND_ALL:
263  {
264  // Disable LOK selection notifications during search.
265  m_pWrtShell->GetSfxViewShell()->setTiledSearching(true);
266  bool bRet = SearchAll();
267  m_pWrtShell->GetSfxViewShell()->setTiledSearching(false);
268 
269  if( !bRet )
270  {
271 #if HAVE_FEATURE_DESKTOP
272  if( !bQuiet )
273  {
274  m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr());
275  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
276  }
277 #endif
278  s_bFound = false;
279  }
281  lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ true);
282  rReq.SetReturnValue(SfxBoolItem(nSlot, bRet));
283 #if HAVE_FEATURE_DESKTOP
284  {
285  pSrchDlg = GetSearchDialog();
286  if (pSrchDlg)
287  {
288  pSrchDlg->SetDocWin(m_pEditWin, eCommand);
289  pSrchDlg->SetSrchFlag(false);
290  }
291  }
292 #endif
293  }
294  break;
295  case SvxSearchCmd::REPLACE:
296  {
297 
298  // 1) Replace selection (Not if only attributes should be replaced)
299 //JP 27.04.95: Why?
300 // what if you only want to assign attributes to the found??
301 
302  SvxSearchCmd nCmd = SvxSearchCmd::FIND;
303  if( !s_pSrchItem->GetReplaceString().isEmpty() ||
304  !s_pReplaceList )
305  {
306  // Prevent, that the replaced string will be found again
307  // if the replacement string is containing the search string.
308  bool bBack = s_pSrchItem->GetBackward();
309  if (bBack)
310  m_pWrtShell->Push();
311  OUString aReplace( s_pSrchItem->GetReplaceString() );
312  i18nutil::SearchOptions2 aTmp( s_pSrchItem->GetSearchOptions() );
314  m_pWrtShell->GetCursor(), m_pWrtShell->GetLayout());
315  if( xBackRef )
316  s_pSrchItem->SetReplaceString( *xBackRef );
317  Replace();
318  if( xBackRef )
319  {
320  s_pSrchItem->SetReplaceString( aReplace );
321  }
322  if (bBack)
323  {
324  m_pWrtShell->Pop();
325  m_pWrtShell->SwapPam();
326  }
327  }
328  else if( s_pReplaceList )
329  nCmd = SvxSearchCmd::REPLACE;
330 
331  // 2) Search further (without replacing!)
332 
333  SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand();
334  s_pSrchItem->SetCommand( nCmd );
335  bool bRet = SearchAndWrap(bQuiet);
336  if( bRet )
337  Scroll( m_pWrtShell->GetCharRect().SVRect());
338  s_pSrchItem->SetCommand( nOldCmd );
339  rReq.SetReturnValue(SfxBoolItem(nSlot, bRet));
340  }
341 #if HAVE_FEATURE_DESKTOP
342  {
343  pSrchDlg = GetSearchDialog();
344  if (pSrchDlg)
345  {
346  pSrchDlg->SetDocWin(m_pEditWin, eCommand);
347  pSrchDlg->SetSrchFlag(false);
348  }
349  }
350 #endif
351  break;
352 
353  case SvxSearchCmd::REPLACE_ALL:
354  {
355  SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
356  s_bExtra = false;
357  sal_uLong nFound;
358 
359  { //Scope for SwWait-Object
360  SwWait aWait( *GetDocShell(), true );
361  m_pWrtShell->StartAllAction();
362 
363  // i#8288 "replace all" should not change cursor
364  // position, so save current cursor
365  m_pWrtShell->Push();
366 
367  if (!s_pSrchItem->GetSelection())
368  {
369  // if we don't want to search in the selection...
370  m_pWrtShell->KillSelection(nullptr, false);
371  if (SwDocPositions::Start == aOpts.eEnd)
372  {
373  m_pWrtShell->EndOfSection();
374  }
375  else
376  {
377  m_pWrtShell->StartOfSection();
378  }
379  }
380  nFound = FUNC_Search( aOpts );
381  // create it just to overwrite it with stack cursor
382  m_pWrtShell->CreateCursor();
383  // i#8288 restore the original cursor position
384  m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
385  m_pWrtShell->EndAllAction();
386  }
387 
388  rReq.SetReturnValue(SfxBoolItem(nSlot, nFound != 0 && ULONG_MAX != nFound));
389  if( !nFound )
390  {
391 #if HAVE_FEATURE_DESKTOP
392  if( !bQuiet )
393  {
394  m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr());
395  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
396  }
397 #endif
398  s_bFound = false;
399  SwView::SetMoveType(nMoveType);
400  return;
401  }
402 
403  if( !bQuiet && ULONG_MAX != nFound)
404  {
405  OUString sText( SwResId( STR_NB_REPLACED ) );
406  sText = sText.replaceFirst("XX", OUString::number( nFound ));
408  }
409  }
410 #if HAVE_FEATURE_DESKTOP
411  pSrchDlg = GetSearchDialog();
412  if (pSrchDlg)
413  {
414  pSrchDlg->SetDocWin(m_pEditWin, eCommand);
415  pSrchDlg->SetSrchFlag(false);
416  }
417 #endif
418  break;
419  }
420 
421  uno::Reference< frame::XDispatchRecorder > xRecorder =
422  GetViewFrame()->GetBindings().GetRecorder();
423  //prevent additional dialogs in recorded macros
424  if ( xRecorder.is() )
425  rReq.AppendItem(SfxBoolItem(SID_SEARCH_QUIET, true));
426 
427  rReq.Done();
428  m_eLastSearchCommand = s_pSrchItem->GetCommand();
429  SwView::SetMoveType(nMoveType);
430  }
431  break;
432  case FID_SEARCH_SEARCHSET:
433  case FID_SEARCH_REPLACESET:
434  {
435  static const sal_uInt16 aNormalAttr[] =
436  {
448 /*22 */ RES_LR_SPACE, RES_UL_SPACE,
449 /*24 */ SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
450 /*26 */ 0
451  };
452 
453  SfxItemSet aSet(m_pWrtShell->GetAttrPool(), aNormalAttr);
454 
455  if( SW_MOD()->GetCTLOptions().IsCTLFontEnabled() )
456  {
457  aSet.MergeRange(RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_WEIGHT);
458  }
459  SvtCJKOptions aCJKOpt;
460  if( aCJKOpt.IsAnyEnabled() )
461  {
462  aSet.MergeRange(RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_WEIGHT);
465  }
466 
467  sal_uInt16 nWhich = SID_SEARCH_SEARCHSET;
468 
469  if ( FID_SEARCH_REPLACESET == nSlot )
470  {
471  nWhich = SID_SEARCH_REPLACESET;
472 
473  if ( s_pReplaceList )
474  {
475  s_pReplaceList->Get( aSet );
476  DELETEZ( s_pReplaceList );
477  }
478  }
479  else if ( s_pSearchList )
480  {
481  s_pSearchList->Get( aSet );
482  DELETEZ( s_pSearchList );
483  }
484  rReq.SetReturnValue( SvxSetItem( nWhich, aSet ) );
485  }
486  break;
487  default:
488  SAL_WARN_IF( nSlot, "sw", "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" );
489  return;
490  }
491 }
492 
493 bool SwView::SearchAndWrap(bool bApi)
494 {
495  SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
496 
497  // Remember starting position of the search for wraparound
498  // Start- / EndAction perhaps because existing selections of 'search all'
499  m_pWrtShell->StartAllAction();
500  m_pWrtShell->Push();
501 
502  // After a search all action we place the cursor at the beginning of
503  // the document so that the single search selects the first matching
504  // occurrence in the document instead of the second.
505  if( m_eLastSearchCommand == SvxSearchCmd::FIND_ALL )
506  {
507  if( SwDocPositions::Start == aOpts.eEnd )
508  m_pWrtShell->EndOfSection();
509  else
510  m_pWrtShell->StartOfSection();
511  }
512 
513  // fdo#65014 : Ensure that the point of the cursor is at the extremity of the
514  // selection closest to the end being searched to as to exclude the selected
515  // region from the search. (This doesn't work in the case of multiple
516  // selected regions as the cursor doesn't mark the selection in that case.)
517  m_pWrtShell->GetCursor()->Normalize( s_pSrchItem->GetBackward() );
518 
519  if (!m_pWrtShell->HasSelection() && (s_pSrchItem->HasStartPoint()))
520  {
521  // No selection -> but we have a start point (top left corner of the
522  // current view), start searching from there, not from the current
523  // cursor position.
524  SwEditShell& rShell = GetWrtShell();
525  Point aPosition(s_pSrchItem->GetStartPointX(), s_pSrchItem->GetStartPointY());
526  rShell.SetCursor(aPosition);
527  }
528 
529  // If you want to search in selected areas, they must not be unselected.
530  if (!s_pSrchItem->GetSelection())
531  m_pWrtShell->KillSelection(nullptr, false);
532 
533  std::unique_ptr<SwWait> pWait(new SwWait( *GetDocShell(), true ));
534  if( FUNC_Search( aOpts ) )
535  {
536  s_bFound = true;
537  if(m_pWrtShell->IsSelFrameMode())
538  {
539  m_pWrtShell->UnSelectFrame();
540  m_pWrtShell->LeaveSelFrameMode();
541  }
542  m_pWrtShell->Pop();
543  m_pWrtShell->EndAllAction();
544  return true;
545  }
546  pWait.reset();
547 
548  // Search in the specialized areas when no search is present in selections.
549  // When searching selections will already searched in these special areas.
550  bool bHasSrchInOther = s_bExtra;
551  if (!s_pSrchItem->GetSelection() && !s_bExtra )
552  {
553  s_bExtra = true;
554  if( FUNC_Search( aOpts ) )
555  {
556  s_bFound = true;
557  m_pWrtShell->Pop();
558  m_pWrtShell->EndAllAction();
559  return true;
560  }
561  s_bExtra = false;
562  }
563  else
564  s_bExtra = !s_bExtra;
565 
566  // If starting position is at the end or beginning of the document.
567  if (aOpts.bDontWrap)
568  {
569  m_pWrtShell->EndAllAction();
570  if( !bApi )
571  {
572 #if HAVE_FEATURE_DESKTOP
573  m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr());
574  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
575 #endif
576  }
577  s_bFound = false;
578  m_pWrtShell->Pop();
579  return false;
580  }
581  m_pWrtShell->EndAllAction();
582  // Try again with WrapAround?
583 
584  m_pWrtShell->StartAllAction();
585  m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
586  pWait.reset(new SwWait( *GetDocShell(), true ));
587 
588  bool bSrchBkwrd = SwDocPositions::Start == aOpts.eEnd;
589 
590  aOpts.eEnd = bSrchBkwrd ? SwDocPositions::Start : SwDocPositions::End;
591  aOpts.eStart = bSrchBkwrd ? SwDocPositions::End : SwDocPositions::Start;
592 
593  if (bHasSrchInOther)
594  {
595  m_pWrtShell->ClearMark();
596  // Select the start or the end of the entire document
597  if (bSrchBkwrd)
598  m_pWrtShell->SttEndDoc(false);
599  else
600  m_pWrtShell->SttEndDoc(true);
601  }
602 
603  s_bFound = bool(FUNC_Search( aOpts ));
604 
605  // If WrapAround found no matches in the body text, search in the special
606  // sections, too.
607  if (!s_bFound && !s_pSrchItem->GetSelection() && !s_bExtra)
608  {
609  s_bExtra = true;
610  if (FUNC_Search(aOpts))
611  s_bFound = true;
612  else
613  s_bExtra = false;
614  }
615 
616  m_pWrtShell->EndAllAction();
617  pWait.reset();
618 #if HAVE_FEATURE_DESKTOP
619  if (s_bFound)
620  {
621  if (!bSrchBkwrd)
622  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End);
623  else
624  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start);
625  }
626  else if(!bApi)
627  {
628  m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr());
629  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
630  }
631 #endif
632  return s_bFound;
633 }
634 
636 {
637  SwWait aWait( *GetDocShell(), true );
638  m_pWrtShell->StartAllAction();
639 
640  SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
641 
642  if (!s_pSrchItem->GetSelection())
643  {
644  // Cancel existing selections, if should not be sought in selected areas.
645  m_pWrtShell->KillSelection(nullptr, false);
646 
647  if( SwDocPositions::Start == aOpts.eEnd )
648  m_pWrtShell->EndOfSection();
649  else
650  m_pWrtShell->StartOfSection();
651  }
652  s_bExtra = false;
653  sal_uInt16 nFound = static_cast<sal_uInt16>(FUNC_Search( aOpts ));
654  s_bFound = 0 != nFound;
655 
656  m_pWrtShell->EndAllAction();
657  return s_bFound;
658 }
659 
661 {
662  SwWait aWait( *GetDocShell(), true );
663 
664  m_pWrtShell->StartAllAction();
665 
666  if( s_pSrchItem->GetPattern() ) // Templates?
667  {
668  SwRewriter aRewriter;
669  aRewriter.AddRule(UndoArg1, s_pSrchItem->GetSearchString());
670  aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
671  aRewriter.AddRule(UndoArg3, s_pSrchItem->GetReplaceString());
672 
673  m_pWrtShell->StartUndo(SwUndoId::UI_REPLACE_STYLE, &aRewriter);
674 
675  m_pWrtShell->SetTextFormatColl( m_pWrtShell->GetParaStyle(
676  s_pSrchItem->GetReplaceString(),
678 
679  m_pWrtShell->EndUndo();
680  }
681  else
682  {
683  if (GetPostItMgr()->HasActiveSidebarWin())
684  GetPostItMgr()->Replace(s_pSrchItem);
685 
686  bool bReqReplace = true;
687 
688  if(m_pWrtShell->HasSelection())
689  {
690  /* check that the selection match the search string*/
691  //save state
692  SwPosition aStartPos = * m_pWrtShell->GetSwCursor()->Start();
693  SwPosition aEndPos = * m_pWrtShell->GetSwCursor()->End();
694  bool bHasSelection = s_pSrchItem->GetSelection();
695  SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand();
696 
697  //set state for checking if current selection has a match
698  s_pSrchItem->SetCommand( SvxSearchCmd::FIND );
699  s_pSrchItem->SetSelection(true);
700 
701  //check if it matches
702  SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
703  if( ! FUNC_Search(aOpts) )
704  {
705 
706  //no matching therefore should not replace selection
707  // => remove selection
708 
709  if(! s_pSrchItem->GetBackward() )
710  {
711  (* m_pWrtShell->GetSwCursor()->Start()) = aStartPos;
712  (* m_pWrtShell->GetSwCursor()->End()) = aEndPos;
713  }
714  else
715  {
716  (* m_pWrtShell->GetSwCursor()->Start()) = aEndPos;
717  (* m_pWrtShell->GetSwCursor()->End()) = aStartPos;
718  }
719  bReqReplace = false;
720  }
721 
722  //set back old search state
723  s_pSrchItem->SetCommand( nOldCmd );
724  s_pSrchItem->SetSelection(bHasSelection);
725  }
726  /*
727  * remove current selection
728  * otherwise it is always replaced
729  * no matter if the search string exists or not in the selection
730  * Now the selection is removed and the next matching string is selected
731  */
732 
733  if( bReqReplace )
734  {
735 
736  bool bReplaced = m_pWrtShell->SwEditShell::Replace( s_pSrchItem->GetReplaceString(),
737  s_pSrchItem->GetRegExp());
738  if( bReplaced && s_pReplaceList && s_pReplaceList->Count() && m_pWrtShell->HasSelection() )
739  {
740  SfxItemSet aReplSet( m_pWrtShell->GetAttrPool(),
742  if( s_pReplaceList->Get( aReplSet ).Count() )
743  {
744  ::SfxToSwPageDescAttr( *m_pWrtShell, aReplSet );
745  m_pWrtShell->SwEditShell::SetAttrSet( aReplSet );
746  }
747  }
748  }
749  }
750 
751  m_pWrtShell->EndAllAction();
752 }
753 
754 SwSearchOptions::SwSearchOptions( SwWrtShell const * pSh, bool bBackward )
755 {
756  eStart = SwDocPositions::Curr;
757  if( bBackward )
758  {
759  eEnd = SwDocPositions::Start;
760  bDontWrap = pSh->IsEndOfDoc();
761  }
762  else
763  {
764  eEnd = SwDocPositions::End;
765  bDontWrap = pSh->IsStartOfDoc();
766  }
767 }
768 
770 {
771 #if HAVE_FEATURE_DESKTOP
772  SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
773 #endif
774  bool bDoReplace = s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE ||
775  s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL;
776 
777  FindRanges eRanges = s_pSrchItem->GetSelection()
779  : s_bExtra
781  if (s_pSrchItem->GetCommand() == SvxSearchCmd::FIND_ALL ||
782  s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL)
783  eRanges |= FindRanges::InSelAll;
784 
785  m_pWrtShell->SttSelect();
786 
787  static const sal_uInt16 aSearchAttrRange[] = {
791  SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
792  0 };
793 
794  SfxItemSet aSrchSet( m_pWrtShell->GetAttrPool(), aSearchAttrRange);
795  if( s_pSearchList && s_pSearchList->Count() )
796  {
797  s_pSearchList->Get( aSrchSet );
798 
799  // -- Page break with page template
800  ::SfxToSwPageDescAttr( *m_pWrtShell, aSrchSet );
801  }
802 
803  std::unique_ptr<SfxItemSet> pReplSet;
804  if( bDoReplace && s_pReplaceList && s_pReplaceList->Count() )
805  {
806  pReplSet.reset( new SfxItemSet( m_pWrtShell->GetAttrPool(),
807  aSearchAttrRange ) );
808  s_pReplaceList->Get( *pReplSet );
809 
810  // -- Page break with page template
811  ::SfxToSwPageDescAttr( *m_pWrtShell, *pReplSet );
812 
813  if( !pReplSet->Count() ) // too bad, we don't know
814  pReplSet.reset(); // the attributes
815  }
816 
817  // build SearchOptions to be used
818 
819  i18nutil::SearchOptions2 aSearchOpt( s_pSrchItem->GetSearchOptions() );
820  aSearchOpt.Locale = GetAppLanguageTag().getLocale();
821  if( !bDoReplace )
822  aSearchOpt.replaceString.clear();
823 
824  sal_uLong nFound;
825  if( aSrchSet.Count() || ( pReplSet && pReplSet->Count() ))
826  {
827  nFound = m_pWrtShell->SearchAttr(
828  aSrchSet,
829  !s_pSrchItem->GetPattern(),
830  rOptions.eStart,
831  rOptions.eEnd,
832  eRanges,
833  !s_pSrchItem->GetSearchString().isEmpty() ? &aSearchOpt : nullptr,
834  pReplSet.get() );
835  }
836  else if( s_pSrchItem->GetPattern() )
837  {
838  // Searching (and replacing) templates
839  const OUString& sRplStr( s_pSrchItem->GetReplaceString() );
840  nFound = m_pWrtShell->SearchTempl( s_pSrchItem->GetSearchString(),
841  rOptions.eStart,
842  rOptions.eEnd,
843  eRanges,
844  bDoReplace ? &sRplStr : nullptr );
845  }
846  else
847  {
848  // Normal search
849  nFound = m_pWrtShell->SearchPattern(aSearchOpt, s_pSrchItem->GetNotes(),
850  rOptions.eStart,
851  rOptions.eEnd,
852  eRanges,
853  bDoReplace );
854  }
855  m_pWrtShell->EndSelect();
856  return nFound;
857 }
858 
860 {
861 #if HAVE_FEATURE_DESKTOP
862  const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId();
864  auto pSrchDlg = pWrp ? pWrp->getDialog() : nullptr;
865  return pSrchDlg;
866 #else
867  return nullptr;
868 #endif
869 }
870 
872 {
873  SfxWhichIter aIter(rSet);
874  sal_uInt16 nWhich = aIter.FirstWhich();
875 
876  while(nWhich)
877  {
878  switch(nWhich)
879  {
880  case SID_SEARCH_OPTIONS:
881  {
882  SearchOptionFlags nOpt = SearchOptionFlags::ALL;
883  if( GetDocShell()->IsReadOnly() )
884  nOpt &= ~SearchOptionFlags( SearchOptionFlags::REPLACE |
885  SearchOptionFlags::REPLACE_ALL );
886  rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS, static_cast<sal_uInt16>(nOpt) ));
887  }
888  break;
889  case SID_SEARCH_ITEM:
890  {
891  if ( !s_pSrchItem )
892  {
893  s_pSrchItem = new SvxSearchItem( SID_SEARCH_ITEM );
894  s_pSrchItem->SetFamily(SfxStyleFamily::Para);
895  s_pSrchItem->SetSearchString( m_pWrtShell->GetSelText() );
896  }
897 
898  if( s_bJustOpened && m_pWrtShell->IsSelection() )
899  {
900  OUString aText;
901  if( 1 == m_pWrtShell->GetCursorCnt() &&
902  !( aText = m_pWrtShell->SwCursorShell::GetSelText() ).isEmpty() )
903  {
904  s_pSrchItem->SetSearchString( aText );
905  s_pSrchItem->SetSelection( false );
906  }
907  else
908  s_pSrchItem->SetSelection( true );
909  }
910 
911  s_bJustOpened = false;
912  rSet.Put( *s_pSrchItem );
913  }
914  break;
915  }
916  nWhich = aIter.NextWhich();
917  }
918 }
919 
920 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwDocPositions eStart
Definition: viewsrch.cxx:79
static void lcl_addContainerToJson(boost::property_tree::ptree &rTree, const OString &rKey, const std::vector< OString > &rMatches)
Adds rMatches using rKey as a key to the rTree tree.
Definition: viewsrch.cxx:86
Marks a position in the document model.
Definition: pam.hxx:35
bool IsAnyEnabled() const
SfxChildWindow * GetChildWindow(sal_uInt16)
static sal_uInt16 GetMoveType()
Definition: viewmdi.cxx:652
SwPaM * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:184
#define RES_CHRATR_RELIEF
Definition: hintids.hxx:105
static void lcl_emitSearchResultCallbacks(SvxSearchItem const *pSearchItem, SwWrtShell const *pWrtShell, bool bHighlightAll)
Emits LOK callbacks (count, selection) for search results.
Definition: viewsrch.cxx:102
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
#define RES_CHRATR_WORDLINEMODE
Definition: hintids.hxx:85
bool IsReadOnly(const OUString &rURL, bool *pbExist)
bool IsStartOfDoc() const
Definition: crsrsh.cxx:2715
boost::optional< OUString > ReplaceBackReferences(const i18nutil::SearchOptions2 &rSearchOpt, SwPaM *const pPam, SwRootFrame const *const pLayout)
Helperfunction to resolve backward references in regular expressions.
Definition: findtxt.cxx:1088
sal_uIntPtr sal_uLong
#define RES_PARATR_VERTALIGN
Definition: hintids.hxx:175
#define RES_PARATR_FORBIDDEN_RULES
Definition: hintids.hxx:174
Find "all" in Footer/Header/Fly...
#define RES_FRMATR_END
Definition: hintids.hxx:238
SAL_DLLPRIVATE void Replace()
Definition: viewsrch.cxx:660
static SvxSearchDialog * GetSearchDialog()
Definition: viewsrch.cxx:859
sal_Int16 nId
#define RES_CHRATR_CJK_WEIGHT
Definition: hintids.hxx:95
sal_uInt16 FirstWhich()
#define RES_PARATR_REGISTER
Definition: hintids.hxx:170
void Done(bool bRemove=false)
#define RES_CHRATR_BLINK
Definition: hintids.hxx:87
OString join(const OString &rSeparator, const std::vector< OString > &rSequence)
#define RES_CHRATR_CJK_FONT
Definition: hintids.hxx:91
SfxViewShell * GetSfxViewShell() const
Definition: viewsh.hxx:444
void StateSearch(SfxItemSet &)
Definition: viewsrch.cxx:871
const SfxItemSet * GetArgs() const
void SfxToSwPageDescAttr(const SwWrtShell &rShell, SfxItemSet &rSet)
Definition: uitool.cxx:610
sal_uInt16 const aTextFormatCollSetRange[]
Definition: init.cxx:150
Find in selections.
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
#define RES_CHRATR_TWO_LINES
Definition: hintids.hxx:103
sal_uInt16 NextWhich()
#define NID_SRCH_REP
Definition: workctrl.hxx:47
SwDocPositions
Definition: cshtyp.hxx:103
Used by the UI to modify the document model.
Definition: wrtsh.hxx:90
#define RES_CHRATR_END
Definition: hintids.hxx:115
void SetSrchFlag(bool bSuccess)
FindRanges
Definition: cshtyp.hxx:90
void libreOfficeKitViewCallback(int nType, const char *pPayload) const override
int SetCursor(const Point &rPt, bool bOnlyText=false, bool bBlock=true)
Definition: crsrsh.cxx:748
#define RES_UL_SPACE
Definition: hintids.hxx:199
#define RES_PARATR_BEGIN
Definition: hintids.hxx:161
#define RES_CHRATR_CASEMAP
Definition: hintids.hxx:70
css::lang::Locale Locale
#define RES_CHRATR_COLOR
Definition: hintids.hxx:72
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
#define RES_CHRATR_OVERLINE
Definition: hintids.hxx:107
#define SW_MOD()
Definition: swmodule.hxx:256
#define RES_CHRATR_BACKGROUND
Definition: hintids.hxx:90
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
#define RES_CHRATR_CTL_FONT
Definition: hintids.hxx:96
SvxSearchCmd GetCommand() const
#define RES_PARATR_HYPHENZONE
Definition: hintids.hxx:168
All (only in non-body and selections).
#define RES_PARATR_SCRIPTSPACE
Definition: hintids.hxx:172
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:29
#define RES_CHRATR_BEGIN
Definition: hintids.hxx:69
sal_uInt16 Count() const
ring_container GetRingContainer()
Definition: ring.hxx:240
OUString SwResId(const char *pId)
Definition: swmodule.cxx:190
static void SetMoveType(sal_uInt16 nSet)
Definition: viewmdi.cxx:657
#define DELETEZ(p)
static void SetSearchLabel(const SearchLabel &rSL)
#define RES_LR_SPACE
Definition: hintids.hxx:198
SAL_DLLPRIVATE bool SearchAndWrap(bool bApi)
Definition: viewsrch.cxx:493
void SetReturnValue(const SfxPoolItem &)
const LanguageTag & GetAppLanguageTag()
Definition: init.cxx:736
#define RES_CHRATR_EMPHASIS_MARK
Definition: hintids.hxx:102
#define RES_CHRATR_ROTATE
Definition: hintids.hxx:101
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_uInt16 GetSlot() const
SAL_DLLPRIVATE sal_uLong FUNC_Search(const SwSearchOptions &rOptions)
Definition: viewsrch.cxx:769
static SfxViewFrame * Current()
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
#define SAL_WARN_IF(condition, area, stream)
#define RES_CHRATR_POSTURE
Definition: hintids.hxx:80
#define RES_CHRATR_CTL_WEIGHT
Definition: hintids.hxx:100
void ExecSearch(SfxRequest &)
Definition: viewsrch.cxx:138
SvxSearchDialog * getDialog()
const OUString & GetSearchString() const
SwDocPositions eEnd
Definition: viewsrch.cxx:79
void SetDocWin(vcl::Window *pDocWin, SvxSearchCmd eCommand)
SvxSearchCmd
#define RES_CHRATR_SHADOWED
Definition: hintids.hxx:82
Find "one" only in body text.
bool IsEndOfDoc() const
Definition: crsrsh.cxx:2727
#define FN_REPEAT_SEARCH
Definition: cmdid.h:102
void AppendItem(const SfxPoolItem &)
const SearchAttrItemList * GetReplaceItemList() const
bool IsAPI() const
#define RES_CHRATR_SCALEW
Definition: hintids.hxx:104
SAL_DLLPRIVATE bool SearchAll()
Definition: viewsrch.cxx:635
#define RES_FRMATR_BEGIN
Definition: hintids.hxx:194
SearchOptionFlags
SwSearchOptions(SwWrtShell const *pSh, bool bBackward)
Definition: viewsrch.cxx:754
#define RES_PARATR_END
Definition: hintids.hxx:181
#define RES_PARATR_LINESPACING
Definition: hintids.hxx:162
const SearchAttrItemList * GetSearchItemList() const