File: | home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx |
Warning: | line 151, column 23 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <string> | |||
21 | ||||
22 | #include <memory> | |||
23 | #include <boost/property_tree/json_parser.hpp> | |||
24 | ||||
25 | #include <hintids.hxx> | |||
26 | ||||
27 | #include <sal/log.hxx> | |||
28 | #include <svl/cjkoptions.hxx> | |||
29 | #include <svl/ctloptions.hxx> | |||
30 | #include <svx/pageitem.hxx> | |||
31 | #include <svl/whiter.hxx> | |||
32 | #include <sfx2/viewfrm.hxx> | |||
33 | #include <svl/eitem.hxx> | |||
34 | #include <svl/srchitem.hxx> | |||
35 | #include <sfx2/bindings.hxx> | |||
36 | #include <sfx2/request.hxx> | |||
37 | #include <svx/srchdlg.hxx> | |||
38 | #include <edtwin.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 | ||||
64 | struct SwSearchOptions | |||
65 | { | |||
66 | SwDocPositions eStart, eEnd; | |||
67 | bool bDontWrap; | |||
68 | ||||
69 | SwSearchOptions( SwWrtShell const * pSh, bool bBackward ); | |||
70 | }; | |||
71 | ||||
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) | |||
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 | ||||
88 | /// Emits LOK callbacks (count, selection) for search results. | |||
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 | ||||
126 | void SwView::ExecSearch(SfxRequest& rReq) | |||
127 | { | |||
128 | const SfxItemSet* pArgs = rReq.GetArgs(); | |||
| ||||
129 | const SfxPoolItem* pItem = nullptr; | |||
130 | bool bQuiet = false; | |||
131 | if(pArgs && SfxItemState::SET == pArgs->GetItemState(SID_SEARCH_QUIET(5000 + 1684), false, &pItem)) | |||
132 | bQuiet = static_cast<const SfxBoolItem*>( pItem)->GetValue(); | |||
133 | ||||
134 | sal_uInt16 nSlot = rReq.GetSlot(); | |||
135 | if (nSlot == FN_REPEAT_SEARCH((20000 + 100) + 50) && !s_pSrchItem) | |||
136 | { | |||
137 | if(bQuiet) | |||
138 | { | |||
139 | rReq.SetReturnValue(SfxBoolItem(nSlot, false)); | |||
140 | nSlot = 0; | |||
141 | } | |||
142 | } | |||
143 | if( m_pWrtShell->IsBlockMode() ) | |||
144 | m_pWrtShell->LeaveBlockMode(); | |||
145 | switch (nSlot) | |||
146 | { | |||
147 | // for now do nothing | |||
148 | case SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291): | |||
149 | { | |||
150 | delete s_pSrchItem; | |||
151 | s_pSrchItem = pArgs->Get(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291)).Clone(); | |||
| ||||
152 | } | |||
153 | break; | |||
154 | ||||
155 | case FID_SEARCH_ON((10000 + 500) + 0): | |||
156 | s_bJustOpened = true; | |||
157 | GetViewFrame()->GetBindings().Invalidate(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291)); | |||
158 | break; | |||
159 | ||||
160 | case FID_SEARCH_OFF((10000 + 500) + 1): | |||
161 | if(pArgs) | |||
162 | { | |||
163 | // Unregister dialog | |||
164 | delete s_pSrchItem; | |||
165 | s_pSrchItem = pArgs->Get(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291)).Clone(); | |||
166 | ||||
167 | s_xSearchList.reset(); | |||
168 | s_xReplaceList.reset(); | |||
169 | ||||
170 | SvxSearchDialog *const pSrchDlg(GetSearchDialog()); | |||
171 | if (pSrchDlg) | |||
172 | { | |||
173 | // We will remember the search-/replace items. | |||
174 | const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList(); | |||
175 | if( nullptr != pList && pList->Count() ) | |||
176 | s_xSearchList.reset(new SearchAttrItemList( *pList )); | |||
177 | ||||
178 | pList = pSrchDlg->GetReplaceItemList(); | |||
179 | if (nullptr != pList && pList->Count()) | |||
180 | s_xReplaceList.reset(new SearchAttrItemList( *pList )); | |||
181 | } | |||
182 | } | |||
183 | break; | |||
184 | ||||
185 | case FN_REPEAT_SEARCH((20000 + 100) + 50): | |||
186 | case FID_SEARCH_NOW((10000 + 500) + 2): | |||
187 | { | |||
188 | sal_uInt16 nMoveType = SwView::GetMoveType(); | |||
189 | { | |||
190 | if(FID_SEARCH_NOW((10000 + 500) + 2) == nSlot && !rReq.IsAPI()) | |||
191 | SwView::SetMoveType(NID_SRCH_REP20014); | |||
192 | } | |||
193 | ||||
194 | SvxSearchDialog * pSrchDlg(GetSearchDialog()); | |||
195 | if (pSrchDlg) | |||
196 | { | |||
197 | s_xSearchList.reset(); | |||
198 | s_xReplaceList.reset(); | |||
199 | ||||
200 | const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList(); | |||
201 | if( nullptr != pList && pList->Count() ) | |||
202 | s_xSearchList.reset(new SearchAttrItemList( *pList )); | |||
203 | ||||
204 | pList = pSrchDlg->GetReplaceItemList(); | |||
205 | if (nullptr != pList && pList->Count()) | |||
206 | s_xReplaceList.reset(new SearchAttrItemList( *pList )); | |||
207 | } | |||
208 | ||||
209 | if (nSlot == FN_REPEAT_SEARCH((20000 + 100) + 50)) | |||
210 | { | |||
211 | OSL_ENSURE(s_pSrchItem, "SearchItem missing")do { if (true && (!(s_pSrchItem))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx" ":" "211" ": "), "%s", "SearchItem missing"); } } while (false ); | |||
212 | if( !s_pSrchItem ) | |||
213 | s_pSrchItem = new SvxSearchItem(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291)); | |||
214 | } | |||
215 | else | |||
216 | { | |||
217 | // Get SearchItem from request | |||
218 | OSL_ENSURE(pArgs, "Args missing")do { if (true && (!(pArgs))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx" ":" "218" ": "), "%s", "Args missing"); } } while (false); | |||
219 | if ( pArgs ) | |||
220 | { | |||
221 | delete s_pSrchItem; | |||
222 | s_pSrchItem = pArgs->Get(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291)).Clone(); | |||
223 | } | |||
224 | } | |||
225 | SvxSearchCmd eCommand = s_pSrchItem->GetCommand(); | |||
226 | switch (eCommand) | |||
227 | { | |||
228 | case SvxSearchCmd::FIND: | |||
229 | { | |||
230 | bool bRet = SearchAndWrap(bQuiet); | |||
231 | if( bRet ) | |||
232 | { | |||
233 | Scroll(m_pWrtShell->GetCharRect().SVRect()); | |||
234 | if (comphelper::LibreOfficeKit::isActive()) | |||
235 | lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ false); | |||
236 | } | |||
237 | rReq.SetReturnValue(SfxBoolItem(nSlot, bRet)); | |||
238 | ||||
239 | GetDocShell()->Broadcast(SfxHint(SfxHintId::SwNavigatorUpdateTracking)); | |||
240 | } | |||
241 | break; | |||
242 | case SvxSearchCmd::FIND_ALL: | |||
243 | { | |||
244 | // Disable LOK selection notifications during search. | |||
245 | m_pWrtShell->GetSfxViewShell()->setTiledSearching(true); | |||
246 | bool bRet = SearchAll(); | |||
247 | m_pWrtShell->GetSfxViewShell()->setTiledSearching(false); | |||
248 | ||||
249 | GetDocShell()->Broadcast( | |||
250 | SfxHint(SfxHintId::SwNavigatorSelectOutlinesWithSelections)); | |||
251 | ||||
252 | if( !bRet ) | |||
253 | { | |||
254 | #if HAVE_FEATURE_DESKTOP1 | |||
255 | if( !bQuiet ) | |||
256 | { | |||
257 | m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); | |||
258 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); | |||
259 | } | |||
260 | #endif | |||
261 | s_bFound = false; | |||
262 | } | |||
263 | else if (comphelper::LibreOfficeKit::isActive()) | |||
264 | lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ true); | |||
265 | rReq.SetReturnValue(SfxBoolItem(nSlot, bRet)); | |||
266 | } | |||
267 | break; | |||
268 | case SvxSearchCmd::REPLACE: | |||
269 | { | |||
270 | ||||
271 | // 1) Replace selection (Not if only attributes should be replaced) | |||
272 | //JP 27.04.95: Why? | |||
273 | // what if you only want to assign attributes to the found?? | |||
274 | ||||
275 | SvxSearchCmd nCmd = SvxSearchCmd::FIND; | |||
276 | if( !s_pSrchItem->GetReplaceString().isEmpty() || | |||
277 | !s_xReplaceList ) | |||
278 | { | |||
279 | // Prevent, that the replaced string will be found again | |||
280 | // if the replacement string is containing the search string. | |||
281 | bool bBack = s_pSrchItem->GetBackward(); | |||
282 | if (bBack) | |||
283 | m_pWrtShell->Push(); | |||
284 | OUString aReplace( s_pSrchItem->GetReplaceString() ); | |||
285 | i18nutil::SearchOptions2 aTmp( s_pSrchItem->GetSearchOptions() ); | |||
286 | std::optional<OUString> xBackRef = sw::ReplaceBackReferences(aTmp, | |||
287 | m_pWrtShell->GetCursor(), m_pWrtShell->GetLayout()); | |||
288 | if( xBackRef ) | |||
289 | s_pSrchItem->SetReplaceString( *xBackRef ); | |||
290 | Replace(); | |||
291 | if( xBackRef ) | |||
292 | { | |||
293 | s_pSrchItem->SetReplaceString( aReplace ); | |||
294 | } | |||
295 | if (bBack) | |||
296 | { | |||
297 | m_pWrtShell->Pop(); | |||
298 | m_pWrtShell->SwapPam(); | |||
299 | } | |||
300 | } | |||
301 | else if( s_xReplaceList ) | |||
302 | nCmd = SvxSearchCmd::REPLACE; | |||
303 | ||||
304 | // 2) Search further (without replacing!) | |||
305 | ||||
306 | SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand(); | |||
307 | s_pSrchItem->SetCommand( nCmd ); | |||
308 | bool bRet = SearchAndWrap(bQuiet); | |||
309 | if( bRet ) | |||
310 | Scroll( m_pWrtShell->GetCharRect().SVRect()); | |||
311 | s_pSrchItem->SetCommand( nOldCmd ); | |||
312 | rReq.SetReturnValue(SfxBoolItem(nSlot, bRet)); | |||
313 | } | |||
314 | break; | |||
315 | ||||
316 | case SvxSearchCmd::REPLACE_ALL: | |||
317 | { | |||
318 | SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); | |||
319 | s_bExtra = false; | |||
320 | sal_uLong nFound; | |||
321 | ||||
322 | { //Scope for SwWait-Object | |||
323 | SwWait aWait( *GetDocShell(), true ); | |||
324 | m_pWrtShell->StartAllAction(); | |||
325 | ||||
326 | // i#8288 "replace all" should not change cursor | |||
327 | // position, so save current cursor | |||
328 | m_pWrtShell->Push(); | |||
329 | ||||
330 | if (!s_pSrchItem->GetSelection()) | |||
331 | { | |||
332 | // if we don't want to search in the selection... | |||
333 | m_pWrtShell->KillSelection(nullptr, false); | |||
334 | if (SwDocPositions::Start == aOpts.eEnd) | |||
335 | { | |||
336 | m_pWrtShell->EndOfSection(); | |||
337 | } | |||
338 | else | |||
339 | { | |||
340 | m_pWrtShell->StartOfSection(); | |||
341 | } | |||
342 | } | |||
343 | nFound = FUNC_Search( aOpts ); | |||
344 | // create it just to overwrite it with stack cursor | |||
345 | m_pWrtShell->CreateCursor(); | |||
346 | // i#8288 restore the original cursor position | |||
347 | m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); | |||
348 | m_pWrtShell->EndAllAction(); | |||
349 | } | |||
350 | ||||
351 | rReq.SetReturnValue(SfxBoolItem(nSlot, nFound != 0 && ULONG_MAX(9223372036854775807L *2UL+1UL) != nFound)); | |||
352 | if( !nFound ) | |||
353 | { | |||
354 | #if HAVE_FEATURE_DESKTOP1 | |||
355 | if( !bQuiet ) | |||
356 | { | |||
357 | m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); | |||
358 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); | |||
359 | } | |||
360 | #endif | |||
361 | s_bFound = false; | |||
362 | SwView::SetMoveType(nMoveType); | |||
363 | return; | |||
364 | } | |||
365 | ||||
366 | if( !bQuiet && ULONG_MAX(9223372036854775807L *2UL+1UL) != nFound) | |||
367 | { | |||
368 | OUString sText( SwResId( STR_NB_REPLACEDreinterpret_cast<char const *>("STR_NB_REPLACED" "\004" u8"Search key replaced XX times.") ) ); | |||
369 | sText = sText.replaceFirst("XX", OUString::number( nFound )); | |||
370 | SvxSearchDialogWrapper::SetSearchLabel(sText); | |||
371 | } | |||
372 | } | |||
373 | break; | |||
374 | } | |||
375 | ||||
376 | uno::Reference< frame::XDispatchRecorder > xRecorder = | |||
377 | GetViewFrame()->GetBindings().GetRecorder(); | |||
378 | //prevent additional dialogs in recorded macros | |||
379 | if ( xRecorder.is() ) | |||
380 | rReq.AppendItem(SfxBoolItem(SID_SEARCH_QUIET(5000 + 1684), true)); | |||
381 | ||||
382 | rReq.Done(); | |||
383 | m_eLastSearchCommand = s_pSrchItem->GetCommand(); | |||
384 | SwView::SetMoveType(nMoveType); | |||
385 | } | |||
386 | break; | |||
387 | case FID_SEARCH_SEARCHSET((10000 + 500) + 4): | |||
388 | case FID_SEARCH_REPLACESET((10000 + 500) + 5): | |||
389 | { | |||
390 | static const sal_uInt16 aNormalAttr[] = | |||
391 | { | |||
392 | /* 0 */ RES_CHRATR_CASEMAP, RES_CHRATR_CASEMAP, | |||
393 | /* 2 */ RES_CHRATR_COLOR, RES_CHRATR_POSTURE, | |||
394 | /* 4 */ RES_CHRATR_SHADOWED, RES_CHRATR_WORDLINEMODE, | |||
395 | /* 6 */ RES_CHRATR_BLINK, RES_CHRATR_BLINK, | |||
396 | /* 8 */ RES_CHRATR_BACKGROUND, RES_CHRATR_BACKGROUND, | |||
397 | /*10 */ RES_CHRATR_ROTATE, RES_CHRATR_ROTATE, | |||
398 | /*12 */ RES_CHRATR_SCALEW, RES_CHRATR_RELIEF, | |||
399 | /*14 */ RES_CHRATR_OVERLINE, RES_CHRATR_OVERLINE, | |||
400 | /*16 */ RES_PARATR_LINESPACING, RES_PARATR_HYPHENZONE, | |||
401 | /*18 */ RES_PARATR_REGISTER, RES_PARATR_REGISTER, | |||
402 | /*20 */ RES_PARATR_VERTALIGN, RES_PARATR_VERTALIGN, | |||
403 | /*22 */ RES_LR_SPACE, RES_UL_SPACE, | |||
404 | /*24 */ SID_ATTR_PARA_MODEL( 10000 + 65 ), SID_ATTR_PARA_KEEP( 10000 + 66 ), | |||
405 | /*26 */ 0 | |||
406 | }; | |||
407 | ||||
408 | SfxItemSet aSet(m_pWrtShell->GetAttrPool(), aNormalAttr); | |||
409 | ||||
410 | if( SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule ::Writer)))->GetCTLOptions().IsCTLFontEnabled() ) | |||
411 | { | |||
412 | aSet.MergeRange(RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_WEIGHT); | |||
413 | } | |||
414 | SvtCJKOptions aCJKOpt; | |||
415 | if( aCJKOpt.IsAnyEnabled() ) | |||
416 | { | |||
417 | aSet.MergeRange(RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_WEIGHT); | |||
418 | aSet.MergeRange(RES_CHRATR_EMPHASIS_MARK, RES_CHRATR_TWO_LINES); | |||
419 | aSet.MergeRange(RES_PARATR_SCRIPTSPACE, RES_PARATR_FORBIDDEN_RULES); | |||
420 | } | |||
421 | ||||
422 | sal_uInt16 nWhich = SID_SEARCH_SEARCHSET( 10000 + 292 ); | |||
423 | ||||
424 | if ( FID_SEARCH_REPLACESET((10000 + 500) + 5) == nSlot ) | |||
425 | { | |||
426 | nWhich = SID_SEARCH_REPLACESET( 10000 + 293 ); | |||
427 | ||||
428 | if ( s_xReplaceList ) | |||
429 | { | |||
430 | s_xReplaceList->Get( aSet ); | |||
431 | s_xReplaceList.reset(); | |||
432 | } | |||
433 | } | |||
434 | else if ( s_xSearchList ) | |||
435 | { | |||
436 | s_xSearchList->Get( aSet ); | |||
437 | s_xSearchList.reset(); | |||
438 | } | |||
439 | rReq.SetReturnValue( SvxSetItem( nWhich, aSet ) ); | |||
440 | } | |||
441 | break; | |||
442 | default: | |||
443 | SAL_WARN_IF( nSlot, "sw", "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" )do { if (true && (nSlot)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "sw")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)") == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx" ":" "443" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw"), ( "/home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx" ":" "443" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx" ":" "443" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw"), ( "/home/maarten/src/libreoffice/core/sw/source/uibase/uiview/viewsrch.cxx" ":" "443" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
444 | return; | |||
445 | } | |||
446 | } | |||
447 | ||||
448 | bool SwView::SearchAndWrap(bool bApi) | |||
449 | { | |||
450 | SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); | |||
451 | ||||
452 | // Remember starting position of the search for wraparound | |||
453 | // Start- / EndAction perhaps because existing selections of 'search all' | |||
454 | m_pWrtShell->StartAllAction(); | |||
455 | m_pWrtShell->Push(); | |||
456 | ||||
457 | // After a search all action we place the cursor at the beginning of | |||
458 | // the document so that the single search selects the first matching | |||
459 | // occurrence in the document instead of the second. | |||
460 | if( m_eLastSearchCommand == SvxSearchCmd::FIND_ALL ) | |||
461 | { | |||
462 | if( SwDocPositions::Start == aOpts.eEnd ) | |||
463 | m_pWrtShell->EndOfSection(); | |||
464 | else | |||
465 | m_pWrtShell->StartOfSection(); | |||
466 | } | |||
467 | ||||
468 | // fdo#65014 : Ensure that the point of the cursor is at the extremity of the | |||
469 | // selection closest to the end being searched to as to exclude the selected | |||
470 | // region from the search. (This doesn't work in the case of multiple | |||
471 | // selected regions as the cursor doesn't mark the selection in that case.) | |||
472 | m_pWrtShell->GetCursor()->Normalize( s_pSrchItem->GetBackward() ); | |||
473 | ||||
474 | if (!m_pWrtShell->HasSelection() && (s_pSrchItem->HasStartPoint())) | |||
475 | { | |||
476 | // No selection -> but we have a start point (top left corner of the | |||
477 | // current view), start searching from there, not from the current | |||
478 | // cursor position. | |||
479 | SwEditShell& rShell = GetWrtShell(); | |||
480 | Point aPosition(s_pSrchItem->GetStartPointX(), s_pSrchItem->GetStartPointY()); | |||
481 | rShell.SetCursor(aPosition); | |||
482 | } | |||
483 | ||||
484 | // If you want to search in selected areas, they must not be unselected. | |||
485 | if (!s_pSrchItem->GetSelection()) | |||
486 | m_pWrtShell->KillSelection(nullptr, false); | |||
487 | ||||
488 | std::unique_ptr<SwWait> pWait(new SwWait( *GetDocShell(), true )); | |||
489 | if( FUNC_Search( aOpts ) ) | |||
490 | { | |||
491 | s_bFound = true; | |||
492 | if(m_pWrtShell->IsSelFrameMode()) | |||
493 | { | |||
494 | m_pWrtShell->UnSelectFrame(); | |||
495 | m_pWrtShell->LeaveSelFrameMode(); | |||
496 | } | |||
497 | m_pWrtShell->Pop(); | |||
498 | m_pWrtShell->EndAllAction(); | |||
499 | return true; | |||
500 | } | |||
501 | pWait.reset(); | |||
502 | ||||
503 | // Search in the specialized areas when no search is present in selections. | |||
504 | // When searching selections will already searched in these special areas. | |||
505 | bool bHasSrchInOther = s_bExtra; | |||
506 | if (!s_pSrchItem->GetSelection() && !s_bExtra ) | |||
507 | { | |||
508 | s_bExtra = true; | |||
509 | if( FUNC_Search( aOpts ) ) | |||
510 | { | |||
511 | s_bFound = true; | |||
512 | m_pWrtShell->Pop(); | |||
513 | m_pWrtShell->EndAllAction(); | |||
514 | return true; | |||
515 | } | |||
516 | s_bExtra = false; | |||
517 | } | |||
518 | else | |||
519 | s_bExtra = !s_bExtra; | |||
520 | ||||
521 | // If starting position is at the end or beginning of the document. | |||
522 | if (aOpts.bDontWrap) | |||
523 | { | |||
524 | m_pWrtShell->EndAllAction(); | |||
525 | if( !bApi ) | |||
526 | { | |||
527 | #if HAVE_FEATURE_DESKTOP1 | |||
528 | m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); | |||
529 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); | |||
530 | #endif | |||
531 | } | |||
532 | s_bFound = false; | |||
533 | m_pWrtShell->Pop(); | |||
534 | return false; | |||
535 | } | |||
536 | m_pWrtShell->EndAllAction(); | |||
537 | // Try again with WrapAround? | |||
538 | ||||
539 | m_pWrtShell->StartAllAction(); | |||
540 | m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); | |||
541 | pWait.reset(new SwWait( *GetDocShell(), true )); | |||
542 | ||||
543 | bool bSrchBkwrd = SwDocPositions::Start == aOpts.eEnd; | |||
544 | ||||
545 | aOpts.eEnd = bSrchBkwrd ? SwDocPositions::Start : SwDocPositions::End; | |||
546 | aOpts.eStart = bSrchBkwrd ? SwDocPositions::End : SwDocPositions::Start; | |||
547 | ||||
548 | if (bHasSrchInOther) | |||
549 | { | |||
550 | m_pWrtShell->ClearMark(); | |||
551 | // Select the start or the end of the entire document | |||
552 | if (bSrchBkwrd) | |||
553 | m_pWrtShell->SttEndDoc(false); | |||
554 | else | |||
555 | m_pWrtShell->SttEndDoc(true); | |||
556 | } | |||
557 | ||||
558 | s_bFound = bool(FUNC_Search( aOpts )); | |||
559 | ||||
560 | // If WrapAround found no matches in the body text, search in the special | |||
561 | // sections, too. | |||
562 | if (!s_bFound && !s_pSrchItem->GetSelection() && !s_bExtra) | |||
563 | { | |||
564 | s_bExtra = true; | |||
565 | if (FUNC_Search(aOpts)) | |||
566 | s_bFound = true; | |||
567 | else | |||
568 | s_bExtra = false; | |||
569 | } | |||
570 | ||||
571 | m_pWrtShell->EndAllAction(); | |||
572 | pWait.reset(); | |||
573 | #if HAVE_FEATURE_DESKTOP1 | |||
574 | if (s_bFound) | |||
575 | { | |||
576 | if (!bSrchBkwrd) | |||
577 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End); | |||
578 | else | |||
579 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start); | |||
580 | } | |||
581 | else if(!bApi) | |||
582 | { | |||
583 | m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); | |||
584 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); | |||
585 | } | |||
586 | #endif | |||
587 | return s_bFound; | |||
588 | } | |||
589 | ||||
590 | bool SwView::SearchAll() | |||
591 | { | |||
592 | SwWait aWait( *GetDocShell(), true ); | |||
593 | m_pWrtShell->StartAllAction(); | |||
594 | ||||
595 | SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); | |||
596 | ||||
597 | if (!s_pSrchItem->GetSelection()) | |||
598 | { | |||
599 | // Cancel existing selections, if should not be sought in selected areas. | |||
600 | m_pWrtShell->KillSelection(nullptr, false); | |||
601 | ||||
602 | if( SwDocPositions::Start == aOpts.eEnd ) | |||
603 | m_pWrtShell->EndOfSection(); | |||
604 | else | |||
605 | m_pWrtShell->StartOfSection(); | |||
606 | } | |||
607 | s_bExtra = false; | |||
608 | sal_uInt16 nFound = static_cast<sal_uInt16>(FUNC_Search( aOpts )); | |||
609 | s_bFound = 0 != nFound; | |||
610 | ||||
611 | m_pWrtShell->EndAllAction(); | |||
612 | return s_bFound; | |||
613 | } | |||
614 | ||||
615 | void SwView::Replace() | |||
616 | { | |||
617 | SwWait aWait( *GetDocShell(), true ); | |||
618 | ||||
619 | m_pWrtShell->StartAllAction(); | |||
620 | ||||
621 | if( s_pSrchItem->GetPattern() ) // Templates? | |||
622 | { | |||
623 | SwRewriter aRewriter; | |||
624 | aRewriter.AddRule(UndoArg1, s_pSrchItem->GetSearchString()); | |||
625 | aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDSreinterpret_cast<char const *>("STR_YIELDS" "\004" u8"→" ))); | |||
626 | aRewriter.AddRule(UndoArg3, s_pSrchItem->GetReplaceString()); | |||
627 | ||||
628 | m_pWrtShell->StartUndo(SwUndoId::UI_REPLACE_STYLE, &aRewriter); | |||
629 | ||||
630 | m_pWrtShell->SetTextFormatColl( m_pWrtShell->GetParaStyle( | |||
631 | s_pSrchItem->GetReplaceString(), | |||
632 | SwWrtShell::GETSTYLE_CREATESOME )); | |||
633 | ||||
634 | m_pWrtShell->EndUndo(); | |||
635 | } | |||
636 | else | |||
637 | { | |||
638 | if (GetPostItMgr()->HasActiveSidebarWin()) | |||
639 | GetPostItMgr()->Replace(s_pSrchItem); | |||
640 | ||||
641 | bool bReqReplace = true; | |||
642 | ||||
643 | if(m_pWrtShell->HasSelection()) | |||
644 | { | |||
645 | /* check that the selection match the search string*/ | |||
646 | //save state | |||
647 | SwPosition aStartPos = * m_pWrtShell->GetSwCursor()->Start(); | |||
648 | SwPosition aEndPos = * m_pWrtShell->GetSwCursor()->End(); | |||
649 | bool bHasSelection = s_pSrchItem->GetSelection(); | |||
650 | SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand(); | |||
651 | ||||
652 | //set state for checking if current selection has a match | |||
653 | s_pSrchItem->SetCommand( SvxSearchCmd::FIND ); | |||
654 | s_pSrchItem->SetSelection(true); | |||
655 | ||||
656 | //check if it matches | |||
657 | SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); | |||
658 | if( ! FUNC_Search(aOpts) ) | |||
659 | { | |||
660 | ||||
661 | //no matching therefore should not replace selection | |||
662 | // => remove selection | |||
663 | ||||
664 | if(! s_pSrchItem->GetBackward() ) | |||
665 | { | |||
666 | (* m_pWrtShell->GetSwCursor()->Start()) = aStartPos; | |||
667 | (* m_pWrtShell->GetSwCursor()->End()) = aEndPos; | |||
668 | } | |||
669 | else | |||
670 | { | |||
671 | (* m_pWrtShell->GetSwCursor()->Start()) = aEndPos; | |||
672 | (* m_pWrtShell->GetSwCursor()->End()) = aStartPos; | |||
673 | } | |||
674 | bReqReplace = false; | |||
675 | } | |||
676 | ||||
677 | //set back old search state | |||
678 | s_pSrchItem->SetCommand( nOldCmd ); | |||
679 | s_pSrchItem->SetSelection(bHasSelection); | |||
680 | } | |||
681 | /* | |||
682 | * remove current selection | |||
683 | * otherwise it is always replaced | |||
684 | * no matter if the search string exists or not in the selection | |||
685 | * Now the selection is removed and the next matching string is selected | |||
686 | */ | |||
687 | ||||
688 | if( bReqReplace ) | |||
689 | { | |||
690 | ||||
691 | bool bReplaced = m_pWrtShell->SwEditShell::Replace( s_pSrchItem->GetReplaceString(), | |||
692 | s_pSrchItem->GetRegExp()); | |||
693 | if( bReplaced && s_xReplaceList && s_xReplaceList->Count() && m_pWrtShell->HasSelection() ) | |||
694 | { | |||
695 | SfxItemSet aReplSet( m_pWrtShell->GetAttrPool(), | |||
696 | aTextFormatCollSetRange ); | |||
697 | if( s_xReplaceList->Get( aReplSet ).Count() ) | |||
698 | { | |||
699 | ::SfxToSwPageDescAttr( *m_pWrtShell, aReplSet ); | |||
700 | m_pWrtShell->SwEditShell::SetAttrSet( aReplSet ); | |||
701 | } | |||
702 | } | |||
703 | } | |||
704 | } | |||
705 | ||||
706 | m_pWrtShell->EndAllAction(); | |||
707 | } | |||
708 | ||||
709 | SwSearchOptions::SwSearchOptions( SwWrtShell const * pSh, bool bBackward ) | |||
710 | : eStart(SwDocPositions::Curr) | |||
711 | { | |||
712 | if( bBackward ) | |||
713 | { | |||
714 | eEnd = SwDocPositions::Start; | |||
715 | bDontWrap = pSh->IsEndOfDoc(); | |||
716 | } | |||
717 | else | |||
718 | { | |||
719 | eEnd = SwDocPositions::End; | |||
720 | bDontWrap = pSh->IsStartOfDoc(); | |||
721 | } | |||
722 | } | |||
723 | ||||
724 | sal_uLong SwView::FUNC_Search( const SwSearchOptions& rOptions ) | |||
725 | { | |||
726 | #if HAVE_FEATURE_DESKTOP1 | |||
727 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); | |||
728 | #endif | |||
729 | bool bDoReplace = s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE || | |||
730 | s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL; | |||
731 | ||||
732 | FindRanges eRanges = s_pSrchItem->GetSelection() | |||
733 | ? FindRanges::InSel | |||
734 | : s_bExtra | |||
735 | ? FindRanges::InOther : FindRanges::InBody; | |||
736 | if (s_pSrchItem->GetCommand() == SvxSearchCmd::FIND_ALL || | |||
737 | s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL) | |||
738 | eRanges |= FindRanges::InSelAll; | |||
739 | ||||
740 | m_pWrtShell->SttSelect(); | |||
741 | ||||
742 | static const sal_uInt16 aSearchAttrRange[] = { | |||
743 | RES_FRMATR_BEGIN, RES_FRMATR_END-1, | |||
744 | RES_CHRATR_BEGIN, RES_CHRATR_END-1, | |||
745 | RES_PARATR_BEGIN, RES_PARATR_END-1, | |||
746 | SID_ATTR_PARA_MODEL( 10000 + 65 ), SID_ATTR_PARA_KEEP( 10000 + 66 ), | |||
747 | 0 }; | |||
748 | ||||
749 | SfxItemSet aSrchSet( m_pWrtShell->GetAttrPool(), aSearchAttrRange); | |||
750 | if( s_xSearchList && s_xSearchList->Count() ) | |||
751 | { | |||
752 | s_xSearchList->Get( aSrchSet ); | |||
753 | ||||
754 | // -- Page break with page template | |||
755 | ::SfxToSwPageDescAttr( *m_pWrtShell, aSrchSet ); | |||
756 | } | |||
757 | ||||
758 | std::unique_ptr<SfxItemSet> pReplSet; | |||
759 | if( bDoReplace && s_xReplaceList && s_xReplaceList->Count() ) | |||
760 | { | |||
761 | pReplSet.reset( new SfxItemSet( m_pWrtShell->GetAttrPool(), | |||
762 | aSearchAttrRange ) ); | |||
763 | s_xReplaceList->Get( *pReplSet ); | |||
764 | ||||
765 | // -- Page break with page template | |||
766 | ::SfxToSwPageDescAttr( *m_pWrtShell, *pReplSet ); | |||
767 | ||||
768 | if( !pReplSet->Count() ) // too bad, we don't know | |||
769 | pReplSet.reset(); // the attributes | |||
770 | } | |||
771 | ||||
772 | // build SearchOptions to be used | |||
773 | ||||
774 | i18nutil::SearchOptions2 aSearchOpt( s_pSrchItem->GetSearchOptions() ); | |||
775 | aSearchOpt.Locale = GetAppLanguageTag().getLocale(); | |||
776 | if( !bDoReplace ) | |||
777 | aSearchOpt.replaceString.clear(); | |||
778 | ||||
779 | sal_uLong nFound; | |||
780 | if( aSrchSet.Count() || ( pReplSet && pReplSet->Count() )) | |||
781 | { | |||
782 | nFound = m_pWrtShell->SearchAttr( | |||
783 | aSrchSet, | |||
784 | !s_pSrchItem->GetPattern(), | |||
785 | rOptions.eStart, | |||
786 | rOptions.eEnd, | |||
787 | eRanges, | |||
788 | !s_pSrchItem->GetSearchString().isEmpty() ? &aSearchOpt : nullptr, | |||
789 | pReplSet.get() ); | |||
790 | } | |||
791 | else if( s_pSrchItem->GetPattern() ) | |||
792 | { | |||
793 | // Searching (and replacing) templates | |||
794 | const OUString& sRplStr( s_pSrchItem->GetReplaceString() ); | |||
795 | nFound = m_pWrtShell->SearchTempl( s_pSrchItem->GetSearchString(), | |||
796 | rOptions.eStart, | |||
797 | rOptions.eEnd, | |||
798 | eRanges, | |||
799 | bDoReplace ? &sRplStr : nullptr ); | |||
800 | } | |||
801 | else | |||
802 | { | |||
803 | // Normal search | |||
804 | nFound = m_pWrtShell->SearchPattern(aSearchOpt, s_pSrchItem->GetNotes(), | |||
805 | rOptions.eStart, | |||
806 | rOptions.eEnd, | |||
807 | eRanges, | |||
808 | bDoReplace ); | |||
809 | } | |||
810 | m_pWrtShell->EndSelect(); | |||
811 | return nFound; | |||
812 | } | |||
813 | ||||
814 | SvxSearchDialog* SwView::GetSearchDialog() | |||
815 | { | |||
816 | #if HAVE_FEATURE_DESKTOP1 | |||
817 | const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId(); | |||
818 | SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>( SfxViewFrame::Current()->GetChildWindow(nId) ); | |||
819 | auto pSrchDlg = pWrp ? pWrp->getDialog() : nullptr; | |||
820 | return pSrchDlg; | |||
821 | #else | |||
822 | return nullptr; | |||
823 | #endif | |||
824 | } | |||
825 | ||||
826 | void SwView::StateSearch(SfxItemSet &rSet) | |||
827 | { | |||
828 | SfxWhichIter aIter(rSet); | |||
829 | sal_uInt16 nWhich = aIter.FirstWhich(); | |||
830 | ||||
831 | while(nWhich) | |||
832 | { | |||
833 | switch(nWhich) | |||
834 | { | |||
835 | case SID_SEARCH_OPTIONS(10000 + 281): | |||
836 | { | |||
837 | SearchOptionFlags nOpt = SearchOptionFlags::ALL; | |||
838 | if( GetDocShell()->IsReadOnly() ) | |||
839 | nOpt &= ~SearchOptionFlags( SearchOptionFlags::REPLACE | | |||
840 | SearchOptionFlags::REPLACE_ALL ); | |||
841 | rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS(10000 + 281), static_cast<sal_uInt16>(nOpt) )); | |||
842 | } | |||
843 | break; | |||
844 | case SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291): | |||
845 | { | |||
846 | if ( !s_pSrchItem ) | |||
847 | { | |||
848 | s_pSrchItem = new SvxSearchItem( SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291) ); | |||
849 | s_pSrchItem->SetFamily(SfxStyleFamily::Para); | |||
850 | s_pSrchItem->SetSearchString( m_pWrtShell->GetSelText() ); | |||
851 | } | |||
852 | ||||
853 | if( s_bJustOpened && m_pWrtShell->IsSelection() ) | |||
854 | { | |||
855 | OUString aText; | |||
856 | if( 1 == m_pWrtShell->GetCursorCnt() && | |||
857 | !( aText = m_pWrtShell->SwCursorShell::GetSelText() ).isEmpty() ) | |||
858 | { | |||
859 | s_pSrchItem->SetSearchString( aText ); | |||
860 | s_pSrchItem->SetSelection( false ); | |||
861 | } | |||
862 | else | |||
863 | s_pSrchItem->SetSelection( true ); | |||
864 | } | |||
865 | ||||
866 | s_bJustOpened = false; | |||
867 | rSet.Put( *s_pSrchItem ); | |||
868 | } | |||
869 | break; | |||
870 | } | |||
871 | nWhich = aIter.NextWhich(); | |||
872 | } | |||
873 | } | |||
874 | ||||
875 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |