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