/src/libreoffice/sd/source/ui/unoidl/unosrch.cxx
Line | Count | Source |
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 <memory> |
21 | | #include <sal/config.h> |
22 | | |
23 | | #include <com/sun/star/drawing/XShapes.hpp> |
24 | | #include <com/sun/star/drawing/XDrawPage.hpp> |
25 | | #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> |
26 | | #include <utility> |
27 | | #include <vcl/svapp.hxx> |
28 | | |
29 | | #include <svx/svdobj.hxx> |
30 | | #include <svx/svdpool.hxx> |
31 | | #include <editeng/unoipset.hxx> |
32 | | #include <editeng/unotext.hxx> |
33 | | #include <tools/debug.hxx> |
34 | | |
35 | | #include <unoprnms.hxx> |
36 | | #include <unosrch.hxx> |
37 | | |
38 | | using namespace ::com::sun::star; |
39 | | |
40 | 0 | #define WID_SEARCH_BACKWARDS 0 |
41 | 0 | #define WID_SEARCH_CASE 1 |
42 | 0 | #define WID_SEARCH_WORDS 2 |
43 | | |
44 | | static std::span<const SfxItemPropertyMapEntry> ImplGetSearchPropertyMap() |
45 | 0 | { |
46 | 0 | static const SfxItemPropertyMapEntry aSearchPropertyMap_Impl[] = |
47 | 0 | { |
48 | 0 | { u"" UNO_NAME_SEARCH_BACKWARDS ""_ustr, WID_SEARCH_BACKWARDS, cppu::UnoType<bool>::get(), 0, 0 }, |
49 | 0 | { u"" UNO_NAME_SEARCH_CASE ""_ustr, WID_SEARCH_CASE, cppu::UnoType<bool>::get(), 0, 0 }, |
50 | 0 | { u"" UNO_NAME_SEARCH_WORDS ""_ustr, WID_SEARCH_WORDS, cppu::UnoType<bool>::get(), 0, 0 }, |
51 | 0 | }; |
52 | |
|
53 | 0 | return aSearchPropertyMap_Impl; |
54 | 0 | } |
55 | | |
56 | | namespace { |
57 | | |
58 | | class SearchContext_impl |
59 | | { |
60 | | uno::Reference< drawing::XShapes > mxShapes; |
61 | | sal_Int32 mnIndex; |
62 | | |
63 | | public: |
64 | | SearchContext_impl(uno::Reference<drawing::XShapes> xShapes) |
65 | 0 | : mxShapes(std::move( xShapes )), mnIndex( -1 ) {} |
66 | | |
67 | | uno::Reference< drawing::XShape > firstShape() |
68 | 0 | { |
69 | 0 | mnIndex = -1; |
70 | 0 | return nextShape(); |
71 | 0 | } |
72 | | |
73 | | uno::Reference< drawing::XShape > nextShape() |
74 | 0 | { |
75 | 0 | uno::Reference< drawing::XShape > xShape; |
76 | 0 | mnIndex++; |
77 | 0 | if( mxShapes.is() && mxShapes->getCount() > mnIndex ) |
78 | 0 | { |
79 | 0 | mxShapes->getByIndex( mnIndex ) >>= xShape; |
80 | 0 | } |
81 | 0 | return xShape; |
82 | 0 | } |
83 | | }; |
84 | | |
85 | | } |
86 | | |
87 | | /* ================================================================= */ |
88 | | /** this class implements a search or replace operation on a given |
89 | | page or a given sdrobj |
90 | | */ |
91 | | |
92 | | SdUnoSearchReplaceShape::SdUnoSearchReplaceShape( drawing::XDrawPage* pPage ) noexcept |
93 | 310k | : mpPage(pPage) |
94 | 310k | { |
95 | 310k | } |
96 | | |
97 | | SdUnoSearchReplaceShape::~SdUnoSearchReplaceShape() noexcept |
98 | 310k | { |
99 | 310k | } |
100 | | |
101 | | // util::XReplaceable |
102 | | uno::Reference< util::XReplaceDescriptor > SAL_CALL SdUnoSearchReplaceShape::createReplaceDescriptor() |
103 | 0 | { |
104 | 0 | return new SdUnoSearchReplaceDescriptor; |
105 | 0 | } |
106 | | |
107 | | sal_Int32 SAL_CALL SdUnoSearchReplaceShape::replaceAll( const uno::Reference< util::XSearchDescriptor >& xDesc ) |
108 | 0 | { |
109 | 0 | SdUnoSearchReplaceDescriptor* pDescr = dynamic_cast<SdUnoSearchReplaceDescriptor*>( xDesc.get() ); |
110 | 0 | if( pDescr == nullptr ) |
111 | 0 | return 0; |
112 | | |
113 | 0 | sal_Int32 nFound = 0; |
114 | |
|
115 | 0 | uno::Reference< drawing::XShapes > xShapes; |
116 | 0 | uno::Reference< drawing::XShape > xShape; |
117 | |
|
118 | 0 | std::vector<SearchContext_impl> aContexts; |
119 | 0 | if(mpPage) |
120 | 0 | { |
121 | 0 | xShapes = mpPage; |
122 | |
|
123 | 0 | if( xShapes->getCount() ) |
124 | 0 | { |
125 | 0 | aContexts.push_back(SearchContext_impl(xShapes)); |
126 | 0 | xShape = aContexts.back().firstShape(); |
127 | 0 | } |
128 | 0 | else |
129 | 0 | { |
130 | 0 | xShapes = nullptr; |
131 | 0 | } |
132 | 0 | } |
133 | |
|
134 | 0 | while( xShape.is() ) |
135 | 0 | { |
136 | | // replace in xShape |
137 | 0 | uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY); |
138 | 0 | uno::Reference< text::XTextRange > xRange = xText; |
139 | 0 | uno::Reference< text::XTextRange > xFound; |
140 | |
|
141 | 0 | while( xRange.is() ) |
142 | 0 | { |
143 | 0 | xFound = Search( xRange, pDescr ); |
144 | 0 | if( !xFound.is() ) |
145 | 0 | break; |
146 | | |
147 | 0 | xFound->setString( pDescr->getReplaceString() ); |
148 | 0 | xRange = xFound->getEnd(); |
149 | 0 | nFound++; |
150 | 0 | } |
151 | | // done with xShape -> get next shape |
152 | | |
153 | | // test if it's a group |
154 | 0 | uno::Reference< drawing::XShapes > xGroupShape( xShape, uno::UNO_QUERY ); |
155 | 0 | if( xGroupShape.is() && ( xGroupShape->getCount() > 0 ) ) |
156 | 0 | { |
157 | 0 | aContexts.push_back(SearchContext_impl(xGroupShape)); |
158 | 0 | xShape = aContexts.back().firstShape(); |
159 | 0 | } |
160 | 0 | else |
161 | 0 | { |
162 | 0 | if (!aContexts.empty()) |
163 | 0 | xShape = aContexts.back().nextShape(); |
164 | 0 | else |
165 | 0 | xShape = nullptr; |
166 | 0 | } |
167 | | |
168 | | // test parent contexts for next shape if none |
169 | | // is found in the current context |
170 | 0 | while (!aContexts.empty() && !xShape.is()) |
171 | 0 | { |
172 | 0 | aContexts.pop_back(); |
173 | 0 | if (!aContexts.empty()) |
174 | 0 | xShape = aContexts.back().nextShape(); |
175 | 0 | } |
176 | 0 | } |
177 | |
|
178 | 0 | return nFound; |
179 | 0 | } |
180 | | |
181 | | // XSearchable |
182 | | uno::Reference< css::util::XSearchDescriptor > SAL_CALL SdUnoSearchReplaceShape::createSearchDescriptor( ) |
183 | 0 | { |
184 | 0 | return new SdUnoSearchReplaceDescriptor; |
185 | 0 | } |
186 | | |
187 | | uno::Reference< css::container::XIndexAccess > SAL_CALL SdUnoSearchReplaceShape::findAll( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) |
188 | 0 | { |
189 | 0 | SdUnoSearchReplaceDescriptor* pDescr = dynamic_cast<SdUnoSearchReplaceDescriptor*>( xDesc.get() ); |
190 | 0 | if( pDescr == nullptr ) |
191 | 0 | return uno::Reference< container::XIndexAccess > (); |
192 | | |
193 | 0 | sal_Int32 nSequence = 32; |
194 | 0 | sal_Int32 nFound = 0; |
195 | |
|
196 | 0 | uno::Sequence < uno::Reference< uno::XInterface > > aSeq( nSequence ); |
197 | |
|
198 | 0 | uno::Reference< uno::XInterface > * pArray = aSeq.getArray(); |
199 | |
|
200 | 0 | uno::Reference< drawing::XShapes > xShapes; |
201 | 0 | uno::Reference< drawing::XShape > xShape; |
202 | |
|
203 | 0 | std::vector<SearchContext_impl> aContexts; |
204 | 0 | if(mpPage) |
205 | 0 | { |
206 | 0 | xShapes = mpPage; |
207 | |
|
208 | 0 | if( xShapes->getCount() > 0 ) |
209 | 0 | { |
210 | 0 | aContexts.push_back(SearchContext_impl(xShapes)); |
211 | 0 | xShape = aContexts.back().firstShape(); |
212 | 0 | } |
213 | 0 | else |
214 | 0 | { |
215 | 0 | xShapes = nullptr; |
216 | 0 | } |
217 | 0 | } |
218 | |
|
219 | 0 | while( xShape.is() ) |
220 | 0 | { |
221 | | // find in xShape |
222 | 0 | uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY); |
223 | 0 | uno::Reference< text::XTextRange > xRange = xText; |
224 | 0 | uno::Reference< text::XTextRange > xFound; |
225 | |
|
226 | 0 | while( xRange.is() ) |
227 | 0 | { |
228 | 0 | xFound = Search( xRange, pDescr ); |
229 | 0 | if( !xFound.is() ) |
230 | 0 | break; |
231 | | |
232 | 0 | if( nFound >= nSequence ) |
233 | 0 | { |
234 | 0 | nSequence += 32; |
235 | 0 | aSeq.realloc( nSequence ); |
236 | 0 | pArray = aSeq.getArray(); |
237 | 0 | } |
238 | |
|
239 | 0 | pArray[nFound++] = xFound; |
240 | |
|
241 | 0 | xRange = xFound->getEnd(); |
242 | 0 | } |
243 | | // done with shape -> get next shape |
244 | | |
245 | | // test if it's a group |
246 | 0 | uno::Reference< drawing::XShapes > xGroupShape; |
247 | 0 | xGroupShape.set( xShape, uno::UNO_QUERY ); |
248 | |
|
249 | 0 | if( xGroupShape.is() && xGroupShape->getCount() > 0 ) |
250 | 0 | { |
251 | 0 | aContexts.push_back(SearchContext_impl(xGroupShape)); |
252 | 0 | xShape = aContexts.back().firstShape(); |
253 | 0 | } |
254 | 0 | else |
255 | 0 | { |
256 | 0 | if (!aContexts.empty()) |
257 | 0 | xShape = aContexts.back().nextShape(); |
258 | 0 | else |
259 | 0 | xShape = nullptr; |
260 | 0 | } |
261 | | |
262 | | // test parent contexts for next shape if none |
263 | | // is found in the current context |
264 | 0 | while (!aContexts.empty() && !xShape.is()) |
265 | 0 | { |
266 | 0 | aContexts.pop_back(); |
267 | 0 | if (!aContexts.empty()) |
268 | 0 | xShape = aContexts.back().nextShape(); |
269 | 0 | } |
270 | 0 | } |
271 | |
|
272 | 0 | if( nFound != nSequence ) |
273 | 0 | aSeq.realloc( nFound ); |
274 | |
|
275 | 0 | uno::Reference<css::container::XIndexAccess> xRet(new SdUnoFindAllAccess(aSeq)); |
276 | 0 | return xRet; |
277 | 0 | } |
278 | | |
279 | | uno::Reference< css::uno::XInterface > SAL_CALL SdUnoSearchReplaceShape::findFirst( const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) |
280 | 0 | { |
281 | 0 | uno::Reference< text::XTextRange > xRange( GetCurrentShape(), uno::UNO_QUERY ); |
282 | 0 | if( xRange.is() ) |
283 | 0 | return findNext( xRange, xDesc ); |
284 | | |
285 | 0 | return uno::Reference< uno::XInterface > (); |
286 | 0 | } |
287 | | |
288 | | uno::Reference< drawing::XShape > SdUnoSearchReplaceShape::GetCurrentShape() const noexcept |
289 | 0 | { |
290 | 0 | uno::Reference< drawing::XShape > xShape; |
291 | |
|
292 | 0 | if( mpPage && mpPage->getCount() > 0) |
293 | 0 | mpPage->getByIndex(0) >>= xShape; |
294 | |
|
295 | 0 | return xShape; |
296 | |
|
297 | 0 | } |
298 | | |
299 | | uno::Reference< css::uno::XInterface > SAL_CALL SdUnoSearchReplaceShape::findNext( const css::uno::Reference< css::uno::XInterface >& xStartAt, const css::uno::Reference< css::util::XSearchDescriptor >& xDesc ) |
300 | 0 | { |
301 | 0 | SdUnoSearchReplaceDescriptor* pDescr = dynamic_cast<SdUnoSearchReplaceDescriptor*>( xDesc.get() ); |
302 | |
|
303 | 0 | uno::Reference< uno::XInterface > xFound; |
304 | |
|
305 | 0 | uno::Reference< text::XTextRange > xRange( xStartAt, uno::UNO_QUERY ); |
306 | 0 | if(pDescr && xRange.is() ) |
307 | 0 | { |
308 | |
|
309 | 0 | uno::Reference< text::XTextRange > xCurrentRange( xStartAt, uno::UNO_QUERY ); |
310 | |
|
311 | 0 | uno::Reference< drawing::XShape > xCurrentShape( GetShape( xCurrentRange ) ); |
312 | |
|
313 | 0 | while(!xFound.is() && xRange.is()) |
314 | 0 | { |
315 | 0 | xFound = Search( xRange, pDescr ); |
316 | 0 | if(!xFound.is()) |
317 | 0 | { |
318 | | // we need a new starting range now |
319 | 0 | xRange = nullptr; |
320 | |
|
321 | 0 | if(mpPage) |
322 | 0 | { |
323 | | // we do a page wide search, so skip to the next shape here |
324 | | // get next shape on our page |
325 | 0 | uno::Reference< drawing::XShape > xFound2( GetNextShape( mpPage, xCurrentShape ) ); |
326 | 0 | if( xFound2.is() && (xFound2.get() != xCurrentShape.get()) ) |
327 | 0 | xCurrentShape = std::move(xFound2); |
328 | 0 | else |
329 | 0 | xCurrentShape = nullptr; |
330 | |
|
331 | 0 | xRange.set( xCurrentShape, uno::UNO_QUERY ); |
332 | 0 | if(!(xCurrentShape.is() && (xRange.is()))) |
333 | 0 | xRange = nullptr; |
334 | 0 | } |
335 | 0 | else |
336 | 0 | { |
337 | | // we search only in this shape, so end search if we have |
338 | | // not found anything |
339 | 0 | } |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | 0 | return xFound; |
344 | 0 | } |
345 | | |
346 | | /** this method returns the shape that follows xCurrentShape in the shape collection xShapes. |
347 | | It steps recursive into groupshapes and returns the xCurrentShape if it is the last |
348 | | shape in this collection */ |
349 | | uno::Reference< drawing::XShape > SdUnoSearchReplaceShape::GetNextShape( const uno::Reference< container::XIndexAccess >& xShapes, const uno::Reference< drawing::XShape >& xCurrentShape ) noexcept |
350 | 0 | { |
351 | 0 | uno::Reference< drawing::XShape > xFound; |
352 | |
|
353 | 0 | if(xShapes.is() && xCurrentShape.is()) |
354 | 0 | { |
355 | 0 | const sal_Int32 nCount = xShapes->getCount(); |
356 | 0 | for( sal_Int32 i = 0; i < nCount; i++ ) |
357 | 0 | { |
358 | 0 | uno::Reference< drawing::XShape > xSearchShape; |
359 | 0 | xShapes->getByIndex(i) >>= xSearchShape; |
360 | |
|
361 | 0 | if( xSearchShape.is() ) |
362 | 0 | { |
363 | 0 | uno::Reference< container::XIndexAccess > xGroup( xSearchShape, uno::UNO_QUERY ); |
364 | |
|
365 | 0 | if( xCurrentShape.get() == xSearchShape.get() ) |
366 | 0 | { |
367 | 0 | if( xGroup.is() && xGroup->getCount() > 0 ) |
368 | 0 | { |
369 | 0 | xGroup->getByIndex( 0 ) >>= xFound; |
370 | 0 | } |
371 | 0 | else |
372 | 0 | { |
373 | 0 | i++; |
374 | 0 | if( i < nCount ) |
375 | 0 | xShapes->getByIndex( i ) >>= xFound; |
376 | 0 | else |
377 | 0 | xFound = xCurrentShape; |
378 | 0 | } |
379 | |
|
380 | 0 | break; |
381 | 0 | } |
382 | 0 | else if( xGroup.is() ) |
383 | 0 | { |
384 | 0 | xFound = GetNextShape( xGroup, xCurrentShape ); |
385 | 0 | if( xFound.is() ) |
386 | 0 | { |
387 | 0 | if( xFound.get() == xCurrentShape.get() ) |
388 | 0 | { |
389 | | // the current shape was found at the end of the group |
390 | 0 | i++; |
391 | 0 | if( i < nCount ) |
392 | 0 | { |
393 | 0 | xShapes->getByIndex(i) >>= xFound; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | break; |
397 | 0 | } |
398 | 0 | } |
399 | 0 | } |
400 | 0 | } |
401 | 0 | } |
402 | |
|
403 | 0 | return xFound; |
404 | 0 | } |
405 | | |
406 | | uno::Reference< text::XTextRange > SdUnoSearchReplaceShape::Search( const uno::Reference< text::XTextRange >& xText, SdUnoSearchReplaceDescriptor* pDescr ) |
407 | 0 | { |
408 | 0 | if(!xText.is()) |
409 | 0 | return uno::Reference< text::XTextRange > (); |
410 | | |
411 | 0 | uno::Reference< text::XText > xParent( xText->getText() ); |
412 | |
|
413 | 0 | if( !xParent.is() ) |
414 | 0 | { |
415 | 0 | xParent.set( xText, uno::UNO_QUERY ); |
416 | 0 | } |
417 | |
|
418 | 0 | const OUString aText( xParent->getString() ); |
419 | |
|
420 | 0 | const sal_Int32 nTextLen = aText.getLength(); |
421 | |
|
422 | 0 | std::unique_ptr<sal_Int32[]> pConvertPos( new sal_Int32[nTextLen+2] ); |
423 | 0 | std::unique_ptr<sal_Int32[]> pConvertPara( new sal_Int32[nTextLen+2] ); |
424 | |
|
425 | 0 | sal_Int32* pPos = pConvertPos.get(); |
426 | 0 | sal_Int32* pPara = pConvertPara.get(); |
427 | |
|
428 | 0 | sal_Int32 nLastPos = 0, nLastPara = 0; |
429 | |
|
430 | 0 | uno::Reference< container::XEnumerationAccess > xEnumAccess( xParent, uno::UNO_QUERY ); |
431 | | |
432 | | // first we fill the arrays with the position and paragraph for every character |
433 | | // inside the text |
434 | 0 | if( xEnumAccess.is() ) |
435 | 0 | { |
436 | 0 | uno::Reference< container::XEnumeration > xParaEnum( xEnumAccess->createEnumeration() ); |
437 | |
|
438 | 0 | while(xParaEnum->hasMoreElements()) |
439 | 0 | { |
440 | 0 | int ndbg = 0; |
441 | 0 | uno::Reference< text::XTextContent > xParagraph( xParaEnum->nextElement(), uno::UNO_QUERY ); |
442 | 0 | if( xParagraph.is() ) |
443 | 0 | xEnumAccess.set(xParagraph, css::uno::UNO_QUERY); |
444 | 0 | else |
445 | 0 | xEnumAccess.clear(); |
446 | |
|
447 | 0 | if( xEnumAccess.is() ) |
448 | 0 | { |
449 | 0 | uno::Reference< container::XEnumeration > xPortionEnum( xEnumAccess->createEnumeration() ); |
450 | 0 | if( xPortionEnum.is() ) |
451 | 0 | { |
452 | 0 | while(xPortionEnum->hasMoreElements()) |
453 | 0 | { |
454 | 0 | uno::Reference< text::XTextRange > xPortion( xPortionEnum->nextElement(), uno::UNO_QUERY ); |
455 | 0 | if( xPortion.is() ) |
456 | 0 | { |
457 | 0 | const OUString aPortion( xPortion->getString() ); |
458 | 0 | const sal_Int32 nLen = aPortion.getLength(); |
459 | |
|
460 | 0 | ESelection aStartSel( GetSelection( xPortion->getStart() ) ); |
461 | 0 | ESelection aEndSel( GetSelection( xPortion->getEnd() ) ); |
462 | | |
463 | | // special case for empty portions with content or length one portions with content (fields) |
464 | 0 | if( (aStartSel.start.nIndex == aEndSel.start.nIndex) || ( (aStartSel.start.nIndex == (aEndSel.start.nIndex - 1)) && (nLen > 1) ) ) |
465 | 0 | { |
466 | 0 | for( sal_Int32 i = 0; i < nLen; i++ ) |
467 | 0 | { |
468 | 0 | if( ndbg < (nTextLen+2) ) |
469 | 0 | { |
470 | 0 | *pPos++ = aStartSel.start.nIndex; |
471 | 0 | *pPara++ = aStartSel.start.nPara; |
472 | |
|
473 | 0 | ndbg += 1; |
474 | 0 | } |
475 | 0 | else |
476 | 0 | { |
477 | 0 | OSL_FAIL( "array overflow while searching" ); |
478 | 0 | } |
479 | 0 | } |
480 | |
|
481 | 0 | nLastPos = aStartSel.start.nIndex; |
482 | 0 | } |
483 | | // normal case |
484 | 0 | else |
485 | 0 | { |
486 | 0 | for( sal_Int32 i = 0; i < nLen; i++ ) |
487 | 0 | { |
488 | 0 | if( ndbg < (nTextLen+2) ) |
489 | 0 | { |
490 | 0 | *pPos++ = aStartSel.start.nIndex++; |
491 | 0 | *pPara++ = aStartSel.start.nPara; |
492 | |
|
493 | 0 | ndbg += 1; |
494 | 0 | } |
495 | 0 | else |
496 | 0 | { |
497 | 0 | OSL_FAIL( "array overflow while searching" ); |
498 | 0 | } |
499 | 0 | } |
500 | |
|
501 | 0 | nLastPos = aStartSel.start.nIndex - 1; |
502 | 0 | DBG_ASSERT( aEndSel.start.nIndex == aStartSel.start.nIndex, "Search is not working" ); |
503 | 0 | } |
504 | 0 | nLastPara = aStartSel.start.nPara; |
505 | 0 | } |
506 | 0 | } |
507 | 0 | } |
508 | 0 | } |
509 | |
|
510 | 0 | if( ndbg < (nTextLen+2) ) |
511 | 0 | { |
512 | 0 | *pPos++ = nLastPos + 1; |
513 | 0 | *pPara++ = nLastPara; |
514 | 0 | } |
515 | 0 | else |
516 | 0 | { |
517 | 0 | OSL_FAIL( "array overflow while searching" ); |
518 | 0 | } |
519 | 0 | } |
520 | 0 | } |
521 | |
|
522 | 0 | ESelection aSel; |
523 | |
|
524 | 0 | if( xText.is() ) |
525 | 0 | aSel = GetSelection( xText ); |
526 | |
|
527 | 0 | sal_Int32 nStartPos; |
528 | 0 | sal_Int32 nEndPos = 0; |
529 | 0 | for( nStartPos = 0; nStartPos < nTextLen; nStartPos++ ) |
530 | 0 | { |
531 | 0 | if( pConvertPara[nStartPos] == aSel.start.nPara && pConvertPos[nStartPos] == aSel.start.nIndex ) |
532 | 0 | break; |
533 | 0 | } |
534 | |
|
535 | 0 | if( !Search( aText, nStartPos, nEndPos, pDescr ) ) |
536 | 0 | return nullptr; |
537 | | |
538 | 0 | if( nStartPos > nTextLen || nEndPos > nTextLen ) |
539 | 0 | { |
540 | 0 | OSL_FAIL("Array overflow while searching!"); |
541 | 0 | return nullptr; |
542 | 0 | } |
543 | | |
544 | 0 | ESelection aSelection( pConvertPara[nStartPos], pConvertPos[nStartPos], |
545 | 0 | pConvertPara[nEndPos], pConvertPos[nEndPos] ); |
546 | |
|
547 | 0 | SvxUnoTextBase* pParent = comphelper::getFromUnoTunnel<SvxUnoTextBase>( xParent ); |
548 | 0 | if(!pParent) |
549 | 0 | return nullptr; |
550 | | |
551 | 0 | rtl::Reference<SvxUnoTextRange> pRange = new SvxUnoTextRange( *pParent ); |
552 | 0 | pRange->SetSelection(aSelection); |
553 | |
|
554 | 0 | return pRange; |
555 | 0 | } |
556 | | |
557 | | bool SdUnoSearchReplaceShape::Search( const OUString& rText, sal_Int32& nStartPos, sal_Int32& nEndPos, SdUnoSearchReplaceDescriptor* pDescr ) noexcept |
558 | 0 | { |
559 | 0 | OUString aSearchStr( pDescr->getSearchString() ); |
560 | 0 | OUString aText( rText ); |
561 | |
|
562 | 0 | if( !pDescr->IsCaseSensitive() ) |
563 | 0 | { |
564 | 0 | aText = aText.toAsciiLowerCase(); |
565 | 0 | aSearchStr = aSearchStr.toAsciiLowerCase(); |
566 | 0 | } |
567 | |
|
568 | 0 | sal_Int32 nFound = aText.indexOf( aSearchStr, nStartPos ); |
569 | 0 | if( nFound != -1 ) |
570 | 0 | { |
571 | 0 | nStartPos = nFound; |
572 | 0 | nEndPos = nFound + aSearchStr.getLength(); |
573 | |
|
574 | 0 | if(pDescr->IsWords()) |
575 | 0 | { |
576 | 0 | if( (nStartPos > 0 && aText[nStartPos-1] > ' ') || |
577 | 0 | (nEndPos < aText.getLength() && aText[nEndPos] > ' ') ) |
578 | 0 | { |
579 | 0 | nStartPos++; |
580 | 0 | return Search( aText, nStartPos, nEndPos, pDescr ); |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | 0 | return true; |
585 | 0 | } |
586 | 0 | else |
587 | 0 | return false; |
588 | 0 | } |
589 | | |
590 | | ESelection SdUnoSearchReplaceShape::GetSelection( const uno::Reference< text::XTextRange >& xTextRange ) noexcept |
591 | 0 | { |
592 | 0 | ESelection aSel; |
593 | 0 | SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xTextRange ); |
594 | |
|
595 | 0 | if(pRange) |
596 | 0 | aSel = pRange->GetSelection(); |
597 | |
|
598 | 0 | return aSel; |
599 | 0 | } |
600 | | |
601 | | uno::Reference< drawing::XShape > SdUnoSearchReplaceShape::GetShape( const uno::Reference< text::XTextRange >& xTextRange ) noexcept |
602 | 0 | { |
603 | 0 | uno::Reference< drawing::XShape > xShape; |
604 | |
|
605 | 0 | if(xTextRange.is()) |
606 | 0 | { |
607 | 0 | uno::Reference< text::XText > xText( xTextRange->getText() ); |
608 | |
|
609 | 0 | if(xText.is()) |
610 | 0 | { |
611 | 0 | do |
612 | 0 | { |
613 | 0 | xShape.set( xText, uno::UNO_QUERY ); |
614 | 0 | if(!xShape.is()) |
615 | 0 | { |
616 | 0 | uno::Reference< text::XText > xParent( xText->getText() ); |
617 | 0 | if(!xParent.is() || xText.get() == xParent.get()) |
618 | 0 | return xShape; |
619 | | |
620 | 0 | xText = std::move(xParent); |
621 | 0 | } |
622 | 0 | } while( !xShape.is() ); |
623 | 0 | } |
624 | 0 | } |
625 | | |
626 | 0 | return xShape; |
627 | 0 | } |
628 | | |
629 | | /* ================================================================= */ |
630 | | /** this class holds the parameters and status of a search or replace |
631 | | operation performed by class SdUnoSearchReplaceShape |
632 | | */ |
633 | | |
634 | | SdUnoSearchReplaceDescriptor::SdUnoSearchReplaceDescriptor() |
635 | 0 | { |
636 | 0 | mpPropSet.reset( new SvxItemPropertySet(ImplGetSearchPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool()) ); |
637 | |
|
638 | 0 | mbBackwards = false; |
639 | 0 | mbCaseSensitive = false; |
640 | 0 | mbWords = false; |
641 | 0 | } |
642 | | |
643 | | SdUnoSearchReplaceDescriptor::~SdUnoSearchReplaceDescriptor() noexcept |
644 | 0 | { |
645 | 0 | } |
646 | | |
647 | | // XSearchDescriptor |
648 | | OUString SAL_CALL SdUnoSearchReplaceDescriptor::getSearchString() |
649 | 0 | { |
650 | 0 | return maSearchStr; |
651 | 0 | } |
652 | | |
653 | | void SAL_CALL SdUnoSearchReplaceDescriptor::setSearchString( const OUString& aString ) |
654 | 0 | { |
655 | 0 | maSearchStr = aString; |
656 | 0 | } |
657 | | |
658 | | // XReplaceDescriptor |
659 | | OUString SAL_CALL SdUnoSearchReplaceDescriptor::getReplaceString() |
660 | 0 | { |
661 | 0 | return maReplaceStr; |
662 | 0 | } |
663 | | |
664 | | void SAL_CALL SdUnoSearchReplaceDescriptor::setReplaceString( const OUString& aReplaceString ) |
665 | 0 | { |
666 | 0 | maReplaceStr = aReplaceString; |
667 | 0 | } |
668 | | |
669 | | // XPropertySet |
670 | | uno::Reference< css::beans::XPropertySetInfo > SAL_CALL SdUnoSearchReplaceDescriptor::getPropertySetInfo() |
671 | 0 | { |
672 | 0 | SolarMutexGuard aGuard; |
673 | 0 | return mpPropSet->getPropertySetInfo(); |
674 | 0 | } |
675 | | |
676 | | void SAL_CALL SdUnoSearchReplaceDescriptor::setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) |
677 | 0 | { |
678 | 0 | SolarMutexGuard aGuard; |
679 | |
|
680 | 0 | const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName); |
681 | |
|
682 | 0 | bool bOk = false; |
683 | |
|
684 | 0 | switch( pEntry ? pEntry->nWID : -1 ) |
685 | 0 | { |
686 | 0 | case WID_SEARCH_BACKWARDS: |
687 | 0 | bOk = (aValue >>= mbBackwards); |
688 | 0 | break; |
689 | 0 | case WID_SEARCH_CASE: |
690 | 0 | bOk = (aValue >>= mbCaseSensitive); |
691 | 0 | break; |
692 | 0 | case WID_SEARCH_WORDS: |
693 | 0 | bOk = (aValue >>= mbWords); |
694 | 0 | break; |
695 | 0 | default: |
696 | 0 | throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this)); |
697 | 0 | } |
698 | | |
699 | 0 | if( !bOk ) |
700 | 0 | throw lang::IllegalArgumentException(); |
701 | 0 | } |
702 | | |
703 | | uno::Any SAL_CALL SdUnoSearchReplaceDescriptor::getPropertyValue( const OUString& PropertyName ) |
704 | 0 | { |
705 | 0 | SolarMutexGuard aGuard; |
706 | |
|
707 | 0 | uno::Any aAny; |
708 | |
|
709 | 0 | const SfxItemPropertyMapEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName); |
710 | |
|
711 | 0 | switch( pEntry ? pEntry->nWID : -1 ) |
712 | 0 | { |
713 | 0 | case WID_SEARCH_BACKWARDS: |
714 | 0 | aAny <<= mbBackwards; |
715 | 0 | break; |
716 | 0 | case WID_SEARCH_CASE: |
717 | 0 | aAny <<= mbCaseSensitive; |
718 | 0 | break; |
719 | 0 | case WID_SEARCH_WORDS: |
720 | 0 | aAny <<= mbWords; |
721 | 0 | break; |
722 | 0 | default: |
723 | 0 | throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this)); |
724 | 0 | } |
725 | | |
726 | 0 | return aAny; |
727 | 0 | } |
728 | | |
729 | 0 | void SAL_CALL SdUnoSearchReplaceDescriptor::addPropertyChangeListener( const OUString& , const css::uno::Reference< css::beans::XPropertyChangeListener >& ) {} |
730 | 0 | void SAL_CALL SdUnoSearchReplaceDescriptor::removePropertyChangeListener( const OUString& , const css::uno::Reference< css::beans::XPropertyChangeListener >& ) {} |
731 | 0 | void SAL_CALL SdUnoSearchReplaceDescriptor::addVetoableChangeListener( const OUString& , const css::uno::Reference< css::beans::XVetoableChangeListener >& ) {} |
732 | 0 | void SAL_CALL SdUnoSearchReplaceDescriptor::removeVetoableChangeListener( const OUString& , const css::uno::Reference< css::beans::XVetoableChangeListener >& ) {} |
733 | | |
734 | | /* ================================================================= */ |
735 | | |
736 | | SdUnoFindAllAccess::SdUnoFindAllAccess( uno::Sequence< uno::Reference< uno::XInterface > > const & rSequence ) noexcept |
737 | 0 | :maSequence( rSequence ) |
738 | 0 | { |
739 | 0 | } |
740 | | |
741 | | SdUnoFindAllAccess::~SdUnoFindAllAccess() noexcept |
742 | 0 | { |
743 | 0 | } |
744 | | |
745 | | // XElementAccess |
746 | | uno::Type SAL_CALL SdUnoFindAllAccess::getElementType() |
747 | 0 | { |
748 | 0 | return cppu::UnoType<text::XTextRange>::get(); |
749 | 0 | } |
750 | | |
751 | | sal_Bool SAL_CALL SdUnoFindAllAccess::hasElements() |
752 | 0 | { |
753 | 0 | return maSequence.hasElements(); |
754 | 0 | } |
755 | | |
756 | | // XIndexAccess |
757 | | sal_Int32 SAL_CALL SdUnoFindAllAccess::getCount() |
758 | 0 | { |
759 | 0 | return maSequence.getLength(); |
760 | 0 | } |
761 | | |
762 | | uno::Any SAL_CALL SdUnoFindAllAccess::getByIndex( sal_Int32 Index ) |
763 | 0 | { |
764 | 0 | if( Index < 0 || Index >= getCount() ) |
765 | 0 | throw lang::IndexOutOfBoundsException(); |
766 | | |
767 | 0 | uno::Any aAny; |
768 | 0 | aAny <<= maSequence[Index]; |
769 | 0 | return aAny; |
770 | 0 | } |
771 | | |
772 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |