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