Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / uiview / viewsrch.cxx
bloba272fae32ee8647a8ae756e769d53b6fef4b66f6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string>
22 #include <memory>
23 #include <boost/property_tree/json_parser.hpp>
25 #include <hintids.hxx>
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>
52 #include <strings.hrc>
53 #include <SwRewriter.hxx>
55 #include <PostItMgr.hxx>
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;
62 //Search Parameter
64 struct SwSearchOptions
66 SwDocPositions eStart, eEnd;
67 bool bDontWrap;
69 SwSearchOptions( SwWrtShell const * pSh, bool bBackward );
72 /// Adds rMatches using rKey as a key to the rTree tree.
73 static void lcl_addContainerToJson(boost::property_tree::ptree& rTree, const OString& rKey, const std::vector<OString>& rMatches)
75 boost::property_tree::ptree aChildren;
77 for (const OString& rMatch : rMatches)
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));
85 rTree.add_child(rKey.getStr(), aChildren);
88 /// Emits LOK callbacks (count, selection) for search results.
89 static void lcl_emitSearchResultCallbacks(SvxSearchItem const * pSearchItem, SwWrtShell const * pWrtShell, bool bHighlightAll)
91 // Emit a callback also about the selection rectangles, grouped by matches.
92 SwPaM* pPaM = pWrtShell->GetCursor();
93 if (!pPaM)
94 return;
96 std::vector<OString> aMatches;
97 for (SwPaM& rPaM : pPaM->GetRingContainer())
99 if (SwShellCursor* pShellCursor = dynamic_cast<SwShellCursor*>(&rPaM))
101 std::vector<OString> aSelectionRectangles;
102 pShellCursor->SwSelPaintRects::Show(&aSelectionRectangles);
103 std::vector<OString> aRect;
104 for (const OString & rSelectionRectangle : aSelectionRectangles)
106 if (rSelectionRectangle.isEmpty())
107 continue;
108 aRect.push_back(rSelectionRectangle);
110 OString sRect = comphelper::string::join("; ", aRect);
111 aMatches.push_back(sRect);
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);
119 std::stringstream aStream;
120 boost::property_tree::write_json(aStream, aTree);
121 OString aPayload( aStream.str() );
123 pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload);
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);
132 void SwView::ExecSearch(SfxRequest& rReq)
134 GetWrtShell().addCurrentPosition();
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();
142 sal_uInt16 nSlot = rReq.GetSlot();
143 if (nSlot == FN_REPEAT_SEARCH && !s_pSrchItem)
145 if(bQuiet)
147 rReq.SetReturnValue(SfxBoolItem(nSlot, false));
148 nSlot = 0;
151 if( m_pWrtShell->IsBlockMode() )
152 m_pWrtShell->LeaveBlockMode();
153 switch (nSlot)
155 // for now do nothing
156 case SID_SEARCH_ITEM:
158 delete s_pSrchItem;
159 s_pSrchItem = pArgs->Get(SID_SEARCH_ITEM).Clone();
161 break;
163 case FID_SEARCH_ON:
164 s_bJustOpened = true;
165 GetViewFrame().GetBindings().Invalidate(SID_SEARCH_ITEM);
166 break;
168 case FID_SEARCH_OFF:
169 if(pArgs)
171 // Unregister dialog
172 delete s_pSrchItem;
173 s_pSrchItem = pArgs->Get(SID_SEARCH_ITEM).Clone();
175 s_xSearchList.reset();
176 s_xReplaceList.reset();
178 SvxSearchDialog *const pSrchDlg(GetSearchDialog());
179 if (pSrchDlg)
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 ));
186 pList = pSrchDlg->GetReplaceItemList();
187 if (nullptr != pList && pList->Count())
188 s_xReplaceList.reset(new SearchAttrItemList( *pList ));
191 break;
193 case FN_REPEAT_SEARCH:
194 case FID_SEARCH_NOW:
196 sal_uInt16 nMoveType = SwView::GetMoveType();
198 if(FID_SEARCH_NOW == nSlot && !rReq.IsAPI())
199 SwView::SetMoveType(NID_SRCH_REP);
202 SvxSearchDialog * pSrchDlg(GetSearchDialog());
203 if (pSrchDlg)
205 s_xSearchList.reset();
206 s_xReplaceList.reset();
208 const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList();
209 if( nullptr != pList && pList->Count() )
210 s_xSearchList.reset(new SearchAttrItemList( *pList ));
212 pList = pSrchDlg->GetReplaceItemList();
213 if (nullptr != pList && pList->Count())
214 s_xReplaceList.reset(new SearchAttrItemList( *pList ));
217 if (nSlot == FN_REPEAT_SEARCH)
219 OSL_ENSURE(s_pSrchItem, "SearchItem missing");
220 if( !s_pSrchItem )
221 s_pSrchItem = new SvxSearchItem(SID_SEARCH_ITEM);
223 else
225 // Get SearchItem from request
226 OSL_ENSURE(pArgs, "Args missing");
227 if ( pArgs )
229 delete s_pSrchItem;
230 s_pSrchItem = pArgs->Get(SID_SEARCH_ITEM).Clone();
233 SvxSearchCmd eCommand = s_pSrchItem->GetCommand();
234 switch (eCommand)
236 case SvxSearchCmd::FIND:
238 bool bRet = SearchAndWrap(bQuiet);
239 if( bRet )
241 Scroll(m_pWrtShell->GetCharRect().SVRect());
242 if (comphelper::LibreOfficeKit::isActive())
243 lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ false);
245 rReq.SetReturnValue(SfxBoolItem(nSlot, bRet));
247 GetDocShell()->Broadcast(SfxHint(SfxHintId::SwNavigatorUpdateTracking));
249 break;
250 case SvxSearchCmd::FIND_ALL:
252 // Disable LOK selection notifications during search.
253 m_pWrtShell->GetSfxViewShell()->setTiledSearching(true);
254 const auto nFound = SearchAll();
255 m_pWrtShell->GetSfxViewShell()->setTiledSearching(false);
257 GetDocShell()->Broadcast(
258 SfxHint(SfxHintId::SwNavigatorUpdateTracking));
259 GetDocShell()->Broadcast(
260 SfxHint(SfxHintId::SwNavigatorSelectOutlinesWithSelections));
262 if (nFound == 0)
264 #if HAVE_FEATURE_DESKTOP
265 if( !bQuiet )
267 m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8());
268 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
270 #endif
271 s_bFound = false;
273 else
275 if (comphelper::LibreOfficeKit::isActive())
276 lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ true);
277 if (!bQuiet)
279 OUString sText(SwResId(STR_SEARCH_KEY_FOUND_TIMES));
280 sText = sText.replaceFirst("%1", OUString::number(nFound));
281 SvxSearchDialogWrapper::SetSearchLabel(sText);
284 rReq.SetReturnValue(SfxBoolItem(nSlot, nFound != 0));
286 break;
287 case SvxSearchCmd::REPLACE:
290 // 1) Replace selection (Not if only attributes should be replaced)
291 //JP 27.04.95: Why?
292 // what if you only want to assign attributes to the found??
294 SvxSearchCmd nCmd = SvxSearchCmd::FIND;
295 if( !s_pSrchItem->GetReplaceString().isEmpty() ||
296 !s_xReplaceList )
298 // Prevent, that the replaced string will be found again
299 // if the replacement string is containing the search string.
300 bool bBack = s_pSrchItem->GetBackward();
301 if (bBack)
302 m_pWrtShell->Push();
303 OUString aReplace( s_pSrchItem->GetReplaceString() );
304 i18nutil::SearchOptions2 aTmp( s_pSrchItem->GetSearchOptions() );
305 std::optional<OUString> xBackRef = sw::ReplaceBackReferences(aTmp,
306 m_pWrtShell->GetCursor(), m_pWrtShell->GetLayout());
307 if( xBackRef )
308 s_pSrchItem->SetReplaceString( *xBackRef );
309 Replace();
310 if( xBackRef )
312 s_pSrchItem->SetReplaceString( aReplace );
314 if (bBack)
316 m_pWrtShell->Pop();
317 m_pWrtShell->SwapPam();
320 else if( s_xReplaceList )
321 nCmd = SvxSearchCmd::REPLACE;
323 // 2) Search further (without replacing!)
325 SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand();
326 s_pSrchItem->SetCommand( nCmd );
327 bool bRet = SearchAndWrap(bQuiet);
328 if( bRet )
329 Scroll( m_pWrtShell->GetCharRect().SVRect());
330 s_pSrchItem->SetCommand( nOldCmd );
331 rReq.SetReturnValue(SfxBoolItem(nSlot, bRet));
333 break;
335 case SvxSearchCmd::REPLACE_ALL:
337 SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
338 s_bExtra = false;
339 sal_uLong nFound;
341 { //Scope for SwWait-Object
342 SwWait aWait( *GetDocShell(), true );
343 m_pWrtShell->StartAllAction();
345 // i#8288 "replace all" should not change cursor
346 // position, so save current cursor
347 m_pWrtShell->Push();
349 if (!s_pSrchItem->GetSelection())
351 // if we don't want to search in the selection...
352 m_pWrtShell->KillSelection(nullptr, false);
353 if (SwDocPositions::Start == aOpts.eEnd)
355 m_pWrtShell->EndOfSection();
357 else
359 m_pWrtShell->StartOfSection();
362 nFound = FUNC_Search( aOpts );
363 // create it just to overwrite it with stack cursor
364 m_pWrtShell->CreateCursor();
365 // i#8288 restore the original cursor position
366 m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
367 m_pWrtShell->EndAllAction();
370 rReq.SetReturnValue(SfxBoolItem(nSlot, nFound != 0 && ULONG_MAX != nFound));
371 if( !nFound )
373 #if HAVE_FEATURE_DESKTOP
374 if( !bQuiet )
376 m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8());
377 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
379 #endif
380 s_bFound = false;
381 SwView::SetMoveType(nMoveType);
382 return;
385 if( !bQuiet && ULONG_MAX != nFound)
387 OUString sText( SwResId( STR_NB_REPLACED ) );
388 sText = sText.replaceFirst("XX", OUString::number( nFound ));
389 SvxSearchDialogWrapper::SetSearchLabel(sText);
392 break;
395 uno::Reference< frame::XDispatchRecorder > xRecorder =
396 GetViewFrame().GetBindings().GetRecorder();
397 //prevent additional dialogs in recorded macros
398 if ( xRecorder.is() )
399 rReq.AppendItem(SfxBoolItem(SID_SEARCH_QUIET, true));
401 rReq.Done();
402 m_eLastSearchCommand = s_pSrchItem->GetCommand();
403 SwView::SetMoveType(nMoveType);
405 break;
406 case FID_SEARCH_SEARCHSET:
407 case FID_SEARCH_REPLACESET:
409 static const WhichRangesContainer aNormalAttr(svl::Items<
410 /* 0 */ RES_CHRATR_CASEMAP, RES_CHRATR_CASEMAP,
411 /* 2 */ RES_CHRATR_COLOR, RES_CHRATR_POSTURE,
412 /* 4 */ RES_CHRATR_SHADOWED, RES_CHRATR_WORDLINEMODE,
413 /* 6 */ RES_CHRATR_BLINK, RES_CHRATR_BLINK,
414 /* 8 */ RES_CHRATR_BACKGROUND, RES_CHRATR_BACKGROUND,
415 /*10 */ RES_CHRATR_ROTATE, RES_CHRATR_ROTATE,
416 /*12 */ RES_CHRATR_SCALEW, RES_CHRATR_RELIEF,
417 /*14 */ RES_CHRATR_OVERLINE, RES_CHRATR_OVERLINE,
418 /*16 */ RES_PARATR_LINESPACING, RES_PARATR_HYPHENZONE,
419 /*18 */ RES_PARATR_REGISTER, RES_PARATR_REGISTER,
420 /*20 */ RES_PARATR_VERTALIGN, RES_PARATR_VERTALIGN,
421 RES_MARGIN_FIRSTLINE, RES_MARGIN_RIGHT,
422 RES_UL_SPACE, RES_UL_SPACE,
423 /*24 */ SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP
426 SfxItemSet aSet(m_pWrtShell->GetAttrPool(), aNormalAttr);
428 if( SvtCTLOptions::IsCTLFontEnabled() )
430 aSet.MergeRange(RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_WEIGHT);
432 if( SvtCJKOptions::IsAnyEnabled() )
434 aSet.MergeRange(RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_WEIGHT);
435 aSet.MergeRange(RES_CHRATR_EMPHASIS_MARK, RES_CHRATR_TWO_LINES);
436 aSet.MergeRange(RES_PARATR_SCRIPTSPACE, RES_PARATR_FORBIDDEN_RULES);
439 TypedWhichId<SvxSetItem> nWhich = SID_SEARCH_SEARCHSET;
441 if ( FID_SEARCH_REPLACESET == nSlot )
443 nWhich = SID_SEARCH_REPLACESET;
445 if ( s_xReplaceList )
447 s_xReplaceList->Get( aSet );
448 s_xReplaceList.reset();
451 else if ( s_xSearchList )
453 s_xSearchList->Get( aSet );
454 s_xSearchList.reset();
456 rReq.SetReturnValue( SvxSetItem( nWhich, aSet ) );
458 break;
459 default:
460 SAL_WARN_IF( nSlot, "sw", "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" );
461 return;
465 bool SwView::SearchAndWrap(bool bApi)
467 SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
469 // Remember starting position of the search for wraparound
470 // Start- / EndAction perhaps because existing selections of 'search all'
471 m_pWrtShell->StartAllAction();
472 m_pWrtShell->Push();
474 // After a search all action we place the cursor at the beginning of
475 // the document so that the single search selects the first matching
476 // occurrence in the document instead of the second.
477 if( m_eLastSearchCommand == SvxSearchCmd::FIND_ALL )
479 if( SwDocPositions::Start == aOpts.eEnd )
480 m_pWrtShell->EndOfSection();
481 else
482 m_pWrtShell->StartOfSection();
485 // fdo#65014 : Ensure that the point of the cursor is at the extremity of the
486 // selection closest to the end being searched to as to exclude the selected
487 // region from the search. (This doesn't work in the case of multiple
488 // selected regions as the cursor doesn't mark the selection in that case.)
489 m_pWrtShell->GetCursor()->Normalize( s_pSrchItem->GetBackward() );
491 if (!m_pWrtShell->HasSelection() && (s_pSrchItem->HasStartPoint()))
493 // No selection -> but we have a start point (top left corner of the
494 // current view), start searching from there, not from the current
495 // cursor position.
496 SwEditShell& rShell = GetWrtShell();
497 Point aPosition(s_pSrchItem->GetStartPointX(), s_pSrchItem->GetStartPointY());
498 rShell.SetCursor(aPosition);
501 // If you want to search in selected areas, they must not be unselected.
502 if (!s_pSrchItem->GetSelection())
503 m_pWrtShell->KillSelection(nullptr, false);
505 std::optional<SwWait> oWait( std::in_place, *GetDocShell(), true );
506 if( FUNC_Search( aOpts ) )
508 s_bFound = true;
509 if(m_pWrtShell->IsSelFrameMode())
511 m_pWrtShell->UnSelectFrame();
512 m_pWrtShell->LeaveSelFrameMode();
514 m_pWrtShell->Pop();
515 m_pWrtShell->EndAllAction();
516 return true;
518 oWait.reset();
520 // Search in the specialized areas when no search is present in selections.
521 // When searching selections will already searched in these special areas.
522 bool bHasSrchInOther = s_bExtra;
523 if (!s_pSrchItem->GetSelection() && !s_bExtra )
525 s_bExtra = true;
526 if( FUNC_Search( aOpts ) )
528 s_bFound = true;
529 m_pWrtShell->Pop();
530 m_pWrtShell->EndAllAction();
531 return true;
533 s_bExtra = false;
535 else
536 s_bExtra = !s_bExtra;
538 // If starting position is at the end or beginning of the document.
539 if (aOpts.bDontWrap)
541 m_pWrtShell->EndAllAction();
542 if( !bApi )
544 #if HAVE_FEATURE_DESKTOP
545 m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8());
546 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
547 #endif
549 s_bFound = false;
550 m_pWrtShell->Pop();
551 return false;
553 m_pWrtShell->EndAllAction();
554 // Try again with WrapAround?
556 m_pWrtShell->StartAllAction();
557 m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
558 oWait.emplace( *GetDocShell(), true );
560 bool bSrchBkwrd = SwDocPositions::Start == aOpts.eEnd;
562 aOpts.eEnd = bSrchBkwrd ? SwDocPositions::Start : SwDocPositions::End;
563 aOpts.eStart = bSrchBkwrd ? SwDocPositions::End : SwDocPositions::Start;
565 if (bHasSrchInOther)
567 m_pWrtShell->ClearMark();
568 // Select the start or the end of the entire document
569 if (bSrchBkwrd)
570 m_pWrtShell->SttEndDoc(false);
571 else
572 m_pWrtShell->SttEndDoc(true);
575 s_bFound = bool(FUNC_Search( aOpts ));
577 // If WrapAround found no matches in the body text, search in the special
578 // sections, too.
579 if (!s_bFound && !s_pSrchItem->GetSelection() && !s_bExtra)
581 s_bExtra = true;
582 if (FUNC_Search(aOpts))
583 s_bFound = true;
584 else
585 s_bExtra = false;
588 m_pWrtShell->EndAllAction();
589 oWait.reset();
590 #if HAVE_FEATURE_DESKTOP
591 if (s_bFound)
593 if (!bSrchBkwrd)
594 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End);
595 else
596 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start);
598 else if(!bApi)
600 m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8());
601 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
603 #endif
604 return s_bFound;
607 sal_uInt16 SwView::SearchAll()
609 SwWait aWait( *GetDocShell(), true );
610 m_pWrtShell->StartAllAction();
612 SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
614 if (!s_pSrchItem->GetSelection())
616 // Cancel existing selections, if should not be sought in selected areas.
617 m_pWrtShell->KillSelection(nullptr, false);
619 if( SwDocPositions::Start == aOpts.eEnd )
620 m_pWrtShell->EndOfSection();
621 else
622 m_pWrtShell->StartOfSection();
624 s_bExtra = false;
625 sal_uInt16 nFound = o3tl::narrowing<sal_uInt16>(FUNC_Search( aOpts ));
626 s_bFound = 0 != nFound;
628 m_pWrtShell->EndAllAction();
629 return nFound;
632 void SwView::Replace()
634 SwWait aWait( *GetDocShell(), true );
636 m_pWrtShell->StartAllAction();
638 if( s_pSrchItem->GetPattern() ) // Templates?
640 SwRewriter aRewriter;
641 aRewriter.AddRule(UndoArg1, s_pSrchItem->GetSearchString());
642 aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
643 aRewriter.AddRule(UndoArg3, s_pSrchItem->GetReplaceString());
645 m_pWrtShell->StartUndo(SwUndoId::UI_REPLACE_STYLE, &aRewriter);
647 m_pWrtShell->SetTextFormatColl( m_pWrtShell->GetParaStyle(
648 s_pSrchItem->GetReplaceString(),
649 SwWrtShell::GETSTYLE_CREATESOME ));
651 m_pWrtShell->EndUndo();
653 else
655 if (GetPostItMgr()->HasActiveSidebarWin())
656 GetPostItMgr()->Replace(s_pSrchItem);
658 bool bReqReplace = true;
660 if(m_pWrtShell->HasSelection())
662 /* check that the selection match the search string*/
663 //save state
664 SwPosition aStartPos = * m_pWrtShell->GetCursor()->Start();
665 SwPosition aEndPos = * m_pWrtShell->GetCursor()->End();
666 bool bHasSelection = s_pSrchItem->GetSelection();
667 SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand();
669 //set state for checking if current selection has a match
670 s_pSrchItem->SetCommand( SvxSearchCmd::FIND );
671 s_pSrchItem->SetSelection(true);
673 //check if it matches
674 SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() );
675 if( ! FUNC_Search(aOpts) )
678 //no matching therefore should not replace selection
679 // => remove selection
681 if(! s_pSrchItem->GetBackward() )
683 (* m_pWrtShell->GetCursor()->Start()) = aStartPos;
684 (* m_pWrtShell->GetCursor()->End()) = aEndPos;
686 else
688 (* m_pWrtShell->GetCursor()->Start()) = aEndPos;
689 (* m_pWrtShell->GetCursor()->End()) = aStartPos;
691 bReqReplace = false;
694 //set back old search state
695 s_pSrchItem->SetCommand( nOldCmd );
696 s_pSrchItem->SetSelection(bHasSelection);
699 * remove current selection
700 * otherwise it is always replaced
701 * no matter if the search string exists or not in the selection
702 * Now the selection is removed and the next matching string is selected
705 if( bReqReplace )
708 bool bReplaced = m_pWrtShell->SwEditShell::Replace( s_pSrchItem->GetReplaceString(),
709 s_pSrchItem->GetRegExp());
710 if( bReplaced && s_xReplaceList && s_xReplaceList->Count() && m_pWrtShell->HasSelection() )
712 SfxItemSet aReplSet( m_pWrtShell->GetAttrPool(),
713 aTextFormatCollSetRange );
714 if( s_xReplaceList->Get( aReplSet ).Count() )
716 ::SfxToSwPageDescAttr( *m_pWrtShell, aReplSet );
717 m_pWrtShell->SwEditShell::SetAttrSet( aReplSet );
723 m_pWrtShell->EndAllAction();
726 SwSearchOptions::SwSearchOptions( SwWrtShell const * pSh, bool bBackward )
727 : eStart(SwDocPositions::Curr)
729 if( bBackward )
731 eEnd = SwDocPositions::Start;
732 bDontWrap = pSh->IsEndOfDoc();
734 else
736 eEnd = SwDocPositions::End;
737 bDontWrap = pSh->IsStartOfDoc();
741 sal_uLong SwView::FUNC_Search( const SwSearchOptions& rOptions )
743 #if HAVE_FEATURE_DESKTOP
744 SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
745 #endif
746 bool bDoReplace = s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE ||
747 s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL;
749 FindRanges eRanges = s_pSrchItem->GetSelection()
750 ? FindRanges::InSel
751 : s_bExtra
752 ? FindRanges::InOther : FindRanges::InBody;
753 if (s_pSrchItem->GetCommand() == SvxSearchCmd::FIND_ALL ||
754 s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL)
755 eRanges |= FindRanges::InSelAll;
757 m_pWrtShell->SttSelect();
759 static const WhichRangesContainer aSearchAttrRange(svl::Items<
760 RES_CHRATR_BEGIN, RES_CHRATR_END-1,
761 RES_PARATR_BEGIN, RES_PARATR_END-1,
762 RES_FRMATR_BEGIN, RES_FRMATR_END-1,
763 SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP
766 SfxItemSet aSrchSet( m_pWrtShell->GetAttrPool(), aSearchAttrRange);
767 if( s_xSearchList && s_xSearchList->Count() )
769 s_xSearchList->Get( aSrchSet );
771 // -- Page break with page template
772 ::SfxToSwPageDescAttr( *m_pWrtShell, aSrchSet );
775 std::optional<SfxItemSet> xReplSet;
776 if( bDoReplace && s_xReplaceList && s_xReplaceList->Count() )
778 xReplSet.emplace( m_pWrtShell->GetAttrPool(), aSearchAttrRange );
779 s_xReplaceList->Get( *xReplSet );
781 // -- Page break with page template
782 ::SfxToSwPageDescAttr( *m_pWrtShell, *xReplSet );
784 if( !xReplSet->Count() ) // too bad, we don't know
785 xReplSet.reset(); // the attributes
788 // build SearchOptions to be used
790 i18nutil::SearchOptions2 aSearchOpt( s_pSrchItem->GetSearchOptions() );
791 aSearchOpt.Locale = GetAppLanguageTag().getLocale();
792 if( !bDoReplace )
793 aSearchOpt.replaceString.clear();
795 sal_Int32 nFound;
796 if( aSrchSet.Count() || ( xReplSet && xReplSet->Count() ))
798 nFound = m_pWrtShell->SearchAttr(
799 aSrchSet,
800 !s_pSrchItem->GetPattern(),
801 rOptions.eStart,
802 rOptions.eEnd,
803 eRanges,
804 !s_pSrchItem->GetSearchString().isEmpty() ? &aSearchOpt : nullptr,
805 xReplSet ? &*xReplSet : nullptr );
807 else if( s_pSrchItem->GetPattern() )
809 // Searching (and replacing) templates
810 const OUString& sRplStr( s_pSrchItem->GetReplaceString() );
811 nFound = m_pWrtShell->SearchTempl( s_pSrchItem->GetSearchString(),
812 rOptions.eStart,
813 rOptions.eEnd,
814 eRanges,
815 bDoReplace ? &sRplStr : nullptr );
817 else
819 // Normal search
820 nFound = m_pWrtShell->SearchPattern(aSearchOpt, s_pSrchItem->GetNotes(),
821 rOptions.eStart,
822 rOptions.eEnd,
823 eRanges,
824 bDoReplace );
826 m_pWrtShell->EndSelect();
827 return nFound;
830 SvxSearchDialog* SwView::GetSearchDialog()
832 #if HAVE_FEATURE_DESKTOP
833 const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId();
834 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
835 if (!pViewFrm)
836 return nullptr;
837 SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>(pViewFrm->GetChildWindow(nId));
838 if (!pWrp)
839 return nullptr;
840 return pWrp->getDialog();
841 #else
842 return nullptr;
843 #endif
846 void SwView::StateSearch(SfxItemSet &rSet)
848 SfxWhichIter aIter(rSet);
849 sal_uInt16 nWhich = aIter.FirstWhich();
851 while(nWhich)
853 switch(nWhich)
855 case SID_SEARCH_OPTIONS:
857 SearchOptionFlags nOpt = SearchOptionFlags::ALL;
858 if( GetDocShell()->IsReadOnly() )
859 nOpt &= ~SearchOptionFlags( SearchOptionFlags::REPLACE |
860 SearchOptionFlags::REPLACE_ALL );
861 rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS, static_cast<sal_uInt16>(nOpt) ));
863 break;
864 case SID_SEARCH_ITEM:
866 if ( !s_pSrchItem )
868 s_pSrchItem = new SvxSearchItem( SID_SEARCH_ITEM );
869 s_pSrchItem->SetFamily(SfxStyleFamily::Para);
870 s_pSrchItem->SetSearchString( m_pWrtShell->GetSelText() );
873 if( s_bJustOpened && m_pWrtShell->IsSelection() )
875 OUString aText;
876 if( 1 == m_pWrtShell->GetCursorCnt() &&
877 !( aText = m_pWrtShell->SwCursorShell::GetSelText() ).isEmpty() )
879 s_pSrchItem->SetSearchString( aText );
880 s_pSrchItem->SetSelection( false );
882 else
883 s_pSrchItem->SetSelection( true );
886 s_bJustOpened = false;
887 rSet.Put( *s_pSrchItem );
889 break;
891 nWhich = aIter.NextWhich();
895 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */