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