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