xref: /aoo42x/main/sd/source/ui/unoidl/unosrch.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sd.hxx"
30 #include <vcl/svapp.hxx>
31 #include <vos/mutex.hxx>
32 
33 #include <svx/unoshape.hxx>
34 #include <svx/svdpool.hxx>
35 #include <svx/unoprov.hxx>
36 #include <editeng/unotext.hxx>
37 
38 #include <comphelper/extract.hxx>
39 #include <rtl/uuid.h>
40 #include <rtl/memory.h>
41 
42 #include "unohelp.hxx"
43 #include "unoprnms.hxx"
44 #include "unosrch.hxx"
45 
46 using namespace ::vos;
47 using namespace ::rtl;
48 using namespace ::com::sun::star;
49 
50 #define WID_SEARCH_BACKWARDS	0
51 #define WID_SEARCH_CASE			1
52 #define WID_SEARCH_WORDS		2
53 
54 const SfxItemPropertyMapEntry* ImplGetSearchPropertyMap()
55 {
56 	static const SfxItemPropertyMapEntry aSearchPropertyMap_Impl[] =
57 	{
58 		{ MAP_CHAR_LEN(UNO_NAME_SEARCH_BACKWARDS),	WID_SEARCH_BACKWARDS,	&::getBooleanCppuType(),	0,	0 },
59 		{ MAP_CHAR_LEN(UNO_NAME_SEARCH_CASE),		WID_SEARCH_CASE,		&::getBooleanCppuType(),	0,	0 },
60 		{ MAP_CHAR_LEN(UNO_NAME_SEARCH_WORDS),		WID_SEARCH_WORDS,		&::getBooleanCppuType(),	0,	0 },
61 		{ 0,0,0,0,0,0}
62 	};
63 
64 	return aSearchPropertyMap_Impl;
65 }
66 
67 class SearchContext_impl
68 {
69 	uno::Reference< drawing::XShapes > mxShapes;
70 	sal_Int32 mnIndex;
71 	SearchContext_impl*	mpParent;
72 
73 public:
74 	SearchContext_impl( uno::Reference< drawing::XShapes >  xShapes, SearchContext_impl* pParent = NULL )
75 		: mxShapes( xShapes ), mnIndex( -1 ), mpParent( pParent ) {}
76 
77 
78 	uno::Reference< drawing::XShape > firstShape()
79 	{
80 		mnIndex = -1;
81 		return nextShape();
82 	}
83 
84 	uno::Reference< drawing::XShape > nextShape()
85 	{
86 		uno::Reference< drawing::XShape >  xShape;
87 		mnIndex++;
88 		if( mxShapes.is() && mxShapes->getCount() > mnIndex )
89 		{
90 			mxShapes->getByIndex( mnIndex ) >>= xShape;
91 		}
92 		return xShape;
93 	}
94 
95 	SearchContext_impl* getParent() const { return mpParent; }
96 };
97 
98 /* ================================================================= */
99 /** this class implements a search or replace operation on a given
100 	page or a given sdrobj
101   */
102 
103 SdUnoSearchReplaceShape::SdUnoSearchReplaceShape( drawing::XDrawPage* pPage ) throw()
104 {
105 	mpPage = pPage;
106 }
107 
108 SdUnoSearchReplaceShape::~SdUnoSearchReplaceShape() throw()
109 {
110 }
111 
112 // util::XReplaceable
113 uno::Reference< util::XReplaceDescriptor > SAL_CALL SdUnoSearchReplaceShape::createReplaceDescriptor()
114 	throw( uno::RuntimeException )
115 {
116 	return new SdUnoSearchReplaceDescriptor(sal_True);
117 }
118 
119 sal_Int32 SAL_CALL SdUnoSearchReplaceShape::replaceAll( const uno::Reference< util::XSearchDescriptor >& xDesc )
120 	throw( uno::RuntimeException )
121 {
122 	SdUnoSearchReplaceDescriptor* pDescr = SdUnoSearchReplaceDescriptor::getImplementation( xDesc );
123 	if( pDescr == NULL )
124 		return 0;
125 
126 	sal_Int32 nFound	= 0;
127 
128 	uno::Reference< drawing::XShapes >  xShapes;
129 	uno::Reference< drawing::XShape >  xShape;
130 
131 	SearchContext_impl* pContext = NULL;
132 	if(mpPage)
133 	{
134 		uno::Reference< drawing::XDrawPage > xPage( mpPage );
135 
136 		xPage->queryInterface( ITYPE( drawing::XShapes ) ) >>= xShapes;
137 
138 		if( xShapes.is() && (xShapes->getCount() > 0) )
139 		{
140 			pContext = new SearchContext_impl( xShapes );
141 			xShape = pContext->firstShape();
142 		}
143 		else
144 		{
145 			xShapes = NULL;
146 		}
147 	}
148 	else
149 	{
150 		xShape = mpShape;
151 	}
152 
153 	while( xShape.is() )
154 	{
155 		// replace in xShape
156 		uno::Reference< text::XText >  xText(xShape, uno::UNO_QUERY);
157 		uno::Reference< text::XTextRange >  xRange(xText, uno::UNO_QUERY);
158 		uno::Reference< text::XTextRange >  xFound;
159 
160 		while( xRange.is() )
161 		{
162 			xFound = Search( xRange, pDescr );
163 			if( !xFound.is() )
164 				break;
165 
166 			xFound->setString( pDescr->getReplaceString() );
167 			xRange = xFound->getEnd();
168 			nFound++;
169 		}
170 		// done with xShape -> get next shape
171 
172 		// test if its a group
173 		uno::Reference< drawing::XShapes > xGroupShape( xShape, uno::UNO_QUERY );
174 		if( xGroupShape.is() && ( xGroupShape->getCount() > 0 ) )
175 		{
176 			pContext = new SearchContext_impl( xGroupShape, pContext );
177 			xShape = pContext->firstShape();
178 		}
179 		else
180 		{
181 			if( pContext )
182 				xShape = pContext->nextShape();
183 			else
184 				xShape = NULL;
185 		}
186 
187 		// test parent contexts for next shape if none
188 		// is found in the current context
189 		while( pContext && !xShape.is() )
190 		{
191 			if( pContext->getParent() )
192 			{
193 				SearchContext_impl* pOldContext = pContext;
194 				pContext = pContext->getParent();
195 				delete pOldContext;
196 				xShape = pContext->nextShape();
197 			}
198 			else
199 			{
200 				delete pContext;
201 				pContext = NULL;
202 				xShape = NULL;
203 			}
204 		}
205 	}
206 
207 	return nFound;
208 }
209 
210 // XSearchable
211 uno::Reference< ::com::sun::star::util::XSearchDescriptor > SAL_CALL SdUnoSearchReplaceShape::createSearchDescriptor(  )
212 	throw(::com::sun::star::uno::RuntimeException)
213 {
214 	return new SdUnoSearchReplaceDescriptor(sal_False);
215 }
216 
217 uno::Reference< ::com::sun::star::container::XIndexAccess > SAL_CALL SdUnoSearchReplaceShape::findAll( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XSearchDescriptor >& xDesc )
218 	throw(::com::sun::star::uno::RuntimeException)
219 {
220 	SdUnoSearchReplaceDescriptor* pDescr = SdUnoSearchReplaceDescriptor::getImplementation( xDesc );
221 	if( pDescr == NULL )
222 		return uno::Reference< container::XIndexAccess > ();
223 
224 
225 	sal_Int32 nSequence = 32;
226 	sal_Int32 nFound    = 0;
227 
228 	uno::Sequence < uno::Reference< uno::XInterface >  > aSeq( nSequence );
229 
230 	uno::Reference< uno::XInterface > * pArray = aSeq.getArray();
231 
232 	uno::Reference< drawing::XShapes >  xShapes;
233 	uno::Reference< drawing::XShape >  xShape;
234 
235 	SearchContext_impl* pContext = NULL;
236 	if(mpPage)
237 	{
238 		uno::Reference< drawing::XDrawPage >  xPage( mpPage );
239 		xPage->queryInterface( ITYPE( drawing::XShapes ) ) >>= xShapes;
240 
241 		if( xShapes.is() && xShapes->getCount() > 0 )
242 		{
243 			pContext = new SearchContext_impl( xShapes );
244 			xShape = pContext->firstShape();
245 		}
246 		else
247 		{
248 			xShapes = NULL;
249 		}
250 	}
251 	else
252 	{
253 		xShape = mpShape;
254 	}
255 	while( xShape.is() )
256 	{
257 		// find in xShape
258 		uno::Reference< text::XText >  xText(xShape, uno::UNO_QUERY);
259 		uno::Reference< text::XTextRange >  xRange(xText, uno::UNO_QUERY);
260 		uno::Reference< text::XTextRange >  xFound;
261 
262 		while( xRange.is() )
263 		{
264 			xFound = Search( xRange, pDescr );
265 			if( !xFound.is() )
266 				break;
267 
268 			if( nFound >= nSequence )
269 			{
270 				nSequence += 32;
271 				aSeq.realloc( nSequence );
272 				pArray = aSeq.getArray();
273 			}
274 
275 			pArray[nFound++] = xFound;
276 
277 			xRange = xFound->getEnd();
278 		}
279 		// done with shape -> get next shape
280 
281 		// test if its a group
282 		uno::Reference< drawing::XShapes >  xGroupShape;
283 		uno::Any aAny( xShape->queryInterface( ITYPE( drawing::XShapes )));
284 
285 		if( (aAny >>= xGroupShape ) && xGroupShape->getCount() > 0 )
286 		{
287 			pContext = new SearchContext_impl( xGroupShape, pContext );
288 			xShape = pContext->firstShape();
289 		}
290 		else
291 		{
292 			if( pContext )
293 				xShape = pContext->nextShape();
294 			else
295 				xShape = NULL;
296 		}
297 
298 		// test parent contexts for next shape if none
299 		// is found in the current context
300 		while( pContext && !xShape.is() )
301 		{
302 			if( pContext->getParent() )
303 			{
304 				SearchContext_impl* pOldContext = pContext;
305 				pContext = pContext->getParent();
306 				delete pOldContext;
307 				xShape = pContext->nextShape();
308 			}
309 			else
310 			{
311 				delete pContext;
312 				pContext = NULL;
313 				xShape = NULL;
314 			}
315 		}
316 	}
317 
318 	if( nFound != nSequence )
319 		aSeq.realloc( nFound );
320 
321 	return (container::XIndexAccess*)new SdUnoFindAllAccess( aSeq );
322 }
323 
324 uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SdUnoSearchReplaceShape::findFirst( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XSearchDescriptor >& xDesc )
325 	throw(::com::sun::star::uno::RuntimeException)
326 {
327 	uno::Reference< text::XTextRange > xRange( GetCurrentShape(), uno::UNO_QUERY );
328 	if( xRange.is() )
329 		return findNext( xRange, xDesc );
330 
331 	return uno::Reference< uno::XInterface > ();
332 }
333 
334 uno::Reference< drawing::XShape >  SdUnoSearchReplaceShape::GetCurrentShape() const throw()
335 {
336 	uno::Reference< drawing::XShape >  xShape;
337 
338 	if( mpPage )
339 	{
340 		uno::Reference< drawing::XDrawPage >  xPage( mpPage );
341 		uno::Reference< container::XIndexAccess >  xShapes( xPage, uno::UNO_QUERY );
342 		if( xShapes.is() )
343 		{
344 			if(xShapes->getCount() > 0)
345 			{
346 				xShapes->getByIndex(0) >>= xShape;
347 			}
348 		}
349 	}
350 	else if( mpShape )
351 	{
352 		xShape = mpShape;
353 	}
354 
355 	return xShape;
356 
357 }
358 
359 uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SdUnoSearchReplaceShape::findNext( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xStartAt, const ::com::sun::star::uno::Reference< ::com::sun::star::util::XSearchDescriptor >& xDesc )
360 	throw(::com::sun::star::uno::RuntimeException)
361 {
362 	SdUnoSearchReplaceDescriptor* pDescr = SdUnoSearchReplaceDescriptor::getImplementation( xDesc );
363 
364 	uno::Reference< uno::XInterface > xFound;
365 
366 	uno::Reference< text::XTextRange > xRange( xStartAt, uno::UNO_QUERY );
367 	if(pDescr && xRange.is() )
368 	{
369 
370 		uno::Reference< text::XTextRange > xCurrentRange( xStartAt, uno::UNO_QUERY );
371 
372 		uno::Reference< drawing::XShape > xCurrentShape( GetShape( xCurrentRange ) );
373 
374 		while(!xFound.is() && xRange.is())
375 		{
376 			xFound = Search( xRange, pDescr );
377 			if(!xFound.is())
378 			{
379 				// we need a new starting range now
380 				xRange = NULL;
381 
382 				if(mpPage)
383 				{
384 					uno::Reference< drawing::XDrawPage >  xPage( mpPage );
385 
386 					// we do a page wide search, so skip to the next shape here
387 					uno::Reference< container::XIndexAccess > xShapes( xPage, uno::UNO_QUERY );
388 
389 					// get next shape on our page
390 					if( xShapes.is() )
391 					{
392 						uno::Reference< drawing::XShape > xFound2( GetNextShape( xShapes, xCurrentShape ) );
393 						if( xFound2.is() && (xFound2.get() != xCurrentShape.get()) )
394 							xCurrentShape = xFound2;
395 						else
396 							xCurrentShape = NULL;
397 
398 						xCurrentShape->queryInterface( ITYPE( text::XTextRange ) ) >>= xRange;
399 						if(!(xCurrentShape.is() && (xRange.is())))
400 							xRange = NULL;
401 					}
402 				}
403 				else
404 				{
405 					// we search only in this shape, so end search if we have
406 					// not found anything
407 				}
408 			}
409 		}
410 	}
411 	return xFound;
412 }
413 
414 /** this method returns the shape that follows xCurrentShape in the shape collection xShapes.
415 	It steps recursive into groupshapes and returns the xCurrentShape if it is the last
416 	shape in this collection */
417 uno::Reference< drawing::XShape >  SdUnoSearchReplaceShape::GetNextShape( uno::Reference< container::XIndexAccess >  xShapes, uno::Reference< drawing::XShape >  xCurrentShape ) throw()
418 {
419 	uno::Reference< drawing::XShape >  xFound;
420 	uno::Any aAny;
421 
422 	if(xShapes.is() && xCurrentShape.is())
423 	{
424 		const sal_Int32 nCount = xShapes->getCount();
425 		for( sal_Int32 i = 0; i < nCount; i++ )
426 		{
427 			uno::Reference< drawing::XShape > xSearchShape;
428 			xShapes->getByIndex(i) >>= xSearchShape;
429 
430 			if( xSearchShape.is() )
431 			{
432 				uno::Reference< container::XIndexAccess > xGroup( xSearchShape, uno::UNO_QUERY );
433 
434 				if( xCurrentShape.get() == xSearchShape.get() )
435 				{
436 					if( xGroup.is() && xGroup->getCount() > 0 )
437 					{
438 						xGroup->getByIndex( 0 ) >>= xFound;
439 					}
440 					else
441 					{
442 						i++;
443 						if( i < nCount )
444 							xShapes->getByIndex( i ) >>= xFound;
445 						else
446 							xFound = xCurrentShape;
447 					}
448 
449 					break;
450 				}
451 				else if( xGroup.is() )
452 				{
453 					xFound = GetNextShape( xGroup, xCurrentShape );
454 					if( xFound.is() )
455 					{
456 						if( xFound.get() == xCurrentShape.get() )
457 						{
458 							// the current shape was found at the end of the group
459 							i++;
460 							if( i < nCount )
461 							{
462 								xShapes->getByIndex(i) >>= xFound;
463 							}
464 						}
465 						break;
466 					}
467 				}
468 			}
469 		}
470 	}
471 
472 	return xFound;
473 }
474 
475 uno::Reference< text::XTextRange >  SdUnoSearchReplaceShape::Search( uno::Reference< text::XTextRange >  xText, SdUnoSearchReplaceDescriptor* pDescr ) throw()
476 {
477 	if(!xText.is())
478 		return uno::Reference< text::XTextRange > ();
479 
480 	uno::Reference< text::XText > xParent( xText->getText() );
481 
482 	if( !xParent.is() )
483 	{
484 		uno::Any aAny( xText->queryInterface( ITYPE( text::XText )) );
485 		aAny >>= xParent;
486 	}
487 
488 	const OUString aText( xParent->getString() );
489 
490 	const sal_Int32 nTextLen = aText.getLength();
491 
492 	sal_Int32* pConvertPos = new sal_Int32[nTextLen+2];
493 	sal_Int32* pConvertPara = new sal_Int32[nTextLen+2];
494 
495 	int ndbg = 0;
496 	const sal_Unicode* pText = aText;
497 
498 	sal_Int32* pPos = pConvertPos;
499 	sal_Int32* pPara = pConvertPara;
500 
501 	sal_Int32 nLastPos = 0, nLastPara = 0;
502 
503 	uno::Reference< container::XEnumerationAccess > xEnumAccess( xParent, uno::UNO_QUERY );
504 
505 	// first we fill the arrys with the position and paragraph for every character
506 	// inside the text
507 	if( xEnumAccess.is() )
508 	{
509 		uno::Reference< container::XEnumeration >  xParaEnum( xEnumAccess->createEnumeration() );
510 
511 		while(xParaEnum->hasMoreElements())
512 		{
513 			uno::Reference< text::XTextContent >  xParagraph( xParaEnum->nextElement(), uno::UNO_QUERY );
514 			if( xParagraph.is() )
515 				xEnumAccess.query( xParagraph );
516 			else
517 				xEnumAccess.clear();
518 
519 			if( xEnumAccess.is() )
520 			{
521 				 uno::Reference< container::XEnumeration >  xPortionEnum( xEnumAccess->createEnumeration() );
522 				 if( xPortionEnum.is() )
523 				 {
524 					while(xPortionEnum->hasMoreElements())
525 					{
526 						uno::Reference< text::XTextRange >  xPortion( xPortionEnum->nextElement(), uno::UNO_QUERY );
527 						if( xPortion.is() )
528 						{
529 							const OUString aPortion( xPortion->getString() );
530 							const sal_Int32 nLen = aPortion.getLength();
531 
532 							ESelection aStartSel( GetSelection( xPortion->getStart() ) );
533 							ESelection aEndSel( GetSelection( xPortion->getEnd() ) );
534 
535 							// special case for empty portions with content or length one portions with content (fields)
536 							if( (aStartSel.nStartPos == aEndSel.nStartPos) || ( (aStartSel.nStartPos == (aEndSel.nStartPos - 1)) && (nLen > 1) ) )
537 							{
538 								for( sal_Int32 i = 0; i < nLen; i++ )
539 								{
540 									if( ndbg < (nTextLen+2) )
541 									{
542 										*pPos++ = aStartSel.nStartPos;
543 										*pPara++ = aStartSel.nStartPara;
544 
545 										ndbg += 1;
546 										pText++;
547 									}
548 									else
549 									{
550 										DBG_ERROR( "array overflow while searching" );
551 									}
552 								}
553 
554 								nLastPos = aStartSel.nStartPos;
555 							}
556 							// normal case
557 							else
558 							{
559 								for( sal_Int32 i = 0; i < nLen; i++ )
560 								{
561 									if( ndbg < (nTextLen+2) )
562 									{
563 										*pPos++ = aStartSel.nStartPos++;
564 										*pPara++ = aStartSel.nStartPara;
565 
566 										ndbg += 1;
567 										pText++;
568 									}
569 									else
570 									{
571 										DBG_ERROR( "array overflow while searching" );
572 									}
573 								}
574 
575 								nLastPos = aStartSel.nStartPos - 1;
576 								DBG_ASSERT( aEndSel.nStartPos == aStartSel.nStartPos, "Search is not working" );
577 							}
578 							nLastPara = aStartSel.nStartPara;
579 						}
580 					}
581 				}
582 			}
583 
584 			if( ndbg < (nTextLen+2) )
585 			{
586 				*pPos++ = nLastPos + 1;
587 				*pPara++ = nLastPara;
588 
589 				ndbg += 1;
590 				pText++;
591 			}
592 			else
593 			{
594 				DBG_ERROR( "array overflow while searching" );
595 			}
596 		}
597 	}
598 
599 	uno::Reference< text::XText >  xFound;
600 	ESelection aSel;
601 
602 	uno::Reference< text::XTextRange > xRangeRef( xText, uno::UNO_QUERY );
603 	if( xRangeRef.is() )
604 		aSel = GetSelection( xRangeRef );
605 
606 	sal_Int32 nStartPos;
607 	sal_Int32 nEndPos   = 0;
608 	for( nStartPos = 0; nStartPos < nTextLen; nStartPos++ )
609 	{
610 		if( pConvertPara[nStartPos] == aSel.nStartPara && pConvertPos[nStartPos] == aSel.nStartPos )
611 			break;
612 	}
613 
614 	if( Search( aText, nStartPos, nEndPos, pDescr ) )
615 	{
616 		if( nStartPos <= nTextLen && nEndPos <= nTextLen )
617 		{
618 			ESelection aSelection( (sal_uInt16)pConvertPara[nStartPos], (sal_uInt16)pConvertPos[nStartPos],
619 							 (sal_uInt16)pConvertPara[nEndPos], (sal_uInt16)pConvertPos[nEndPos] );
620 			SvxUnoTextRange *pRange;
621 
622 			SvxUnoTextBase* pParent = SvxUnoTextBase::getImplementation( xParent );
623 
624 			if(pParent)
625 			{
626 				pRange = new SvxUnoTextRange( *pParent );
627 				xFound = (text::XText*)pRange;
628 				pRange->SetSelection(aSelection);
629 
630 //				pDescr->SetStartPos( nEndPos );
631 			}
632 		}
633 		else
634 		{
635 			DBG_ERROR("Array overflow while searching!");
636 		}
637 	}
638 
639 	delete[] pConvertPos;
640 	delete[] pConvertPara;
641 
642 	return uno::Reference< text::XTextRange > ( xFound, uno::UNO_QUERY );
643 }
644 
645 sal_Bool SdUnoSearchReplaceShape::Search( const OUString& rText, sal_Int32& nStartPos, sal_Int32& nEndPos, SdUnoSearchReplaceDescriptor* pDescr ) throw()
646 {
647 	OUString aSearchStr( pDescr->getSearchString() );
648 	OUString aText( rText );
649 
650 	if( !pDescr->IsCaseSensitive() )
651 	{
652 		aText.toAsciiLowerCase();
653 		aSearchStr.toAsciiLowerCase();
654 	}
655 
656 	sal_Int32 nFound = aText.indexOf( aSearchStr, nStartPos );
657 	if( nFound != -1 )
658 	{
659 		nStartPos = nFound;
660 		nEndPos   = nFound + aSearchStr.getLength();
661 
662 		if(pDescr->IsWords())
663 		{
664 			if( (nStartPos > 0 && aText.getStr()[nStartPos-1] > ' ') ||
665 				(nEndPos < aText.getLength() && aText.getStr()[nEndPos] > ' ') )
666 			{
667 				nStartPos++;
668 				return Search( aText, nStartPos, nEndPos, pDescr );
669 			}
670 		}
671 
672 		return sal_True;
673 	}
674 	else
675 		return sal_False;
676 }
677 
678 ESelection SdUnoSearchReplaceShape::GetSelection( uno::Reference< text::XTextRange >  xTextRange ) throw()
679 {
680 	ESelection aSel;
681 	SvxUnoTextRangeBase* pRange = SvxUnoTextRangeBase::getImplementation( xTextRange );
682 
683 	if(pRange)
684 		aSel = pRange->GetSelection();
685 
686 	return aSel;
687 }
688 
689 uno::Reference< drawing::XShape >  SdUnoSearchReplaceShape::GetShape( uno::Reference< text::XTextRange >  xTextRange ) throw()
690 {
691 	uno::Reference< drawing::XShape >  xShape;
692 
693 	if(xTextRange.is())
694 	{
695 		uno::Reference< text::XText >  xText( xTextRange->getText() );
696 
697 		if(xText.is())
698 		{
699 			do
700 			{
701 				xText->queryInterface( ITYPE( drawing::XShape )) >>= xShape;
702 				if(!xShape.is())
703 				{
704 					uno::Reference< text::XText > xParent( xText->getText() );
705 					if(!xParent.is() || xText.get() == xParent.get())
706 						return xShape;
707 
708 					xText = xParent;
709 				}
710 			} while( !xShape.is() );
711 		}
712 	}
713 
714 	return xShape;
715 }
716 
717 /* ================================================================= */
718 /** this class holds the parameters and status of a search or replace
719 	operation performed by class SdUnoSearchReplaceShape
720   */
721 
722 UNO3_GETIMPLEMENTATION_IMPL( SdUnoSearchReplaceDescriptor );
723 
724 SdUnoSearchReplaceDescriptor::SdUnoSearchReplaceDescriptor( sal_Bool bReplace ) throw()
725 {
726 	mpPropSet = new SvxItemPropertySet(ImplGetSearchPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool());
727 
728 	mbBackwards = sal_False;
729 	mbCaseSensitive = sal_False;
730 	mbWords = sal_False;
731 
732 	mbReplace = bReplace;
733 }
734 
735 SdUnoSearchReplaceDescriptor::~SdUnoSearchReplaceDescriptor() throw()
736 {
737 	delete mpPropSet;
738 }
739 
740 // XSearchDescriptor
741 OUString SAL_CALL SdUnoSearchReplaceDescriptor::getSearchString()
742 	throw(::com::sun::star::uno::RuntimeException)
743 {
744 	return maSearchStr;
745 }
746 
747 void SAL_CALL SdUnoSearchReplaceDescriptor::setSearchString( const OUString& aString )
748 	throw(::com::sun::star::uno::RuntimeException)
749 {
750 	maSearchStr = aString;
751 }
752 
753 // XReplaceDescriptor
754 OUString SAL_CALL SdUnoSearchReplaceDescriptor::getReplaceString()
755 	throw(::com::sun::star::uno::RuntimeException)
756 {
757 	return maReplaceStr;
758 }
759 
760 void SAL_CALL SdUnoSearchReplaceDescriptor::setReplaceString( const ::rtl::OUString& aReplaceString )
761 	throw(::com::sun::star::uno::RuntimeException)
762 {
763 	maReplaceStr = aReplaceString;
764 }
765 
766 // XPropertySet
767 uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL SdUnoSearchReplaceDescriptor::getPropertySetInfo()
768 	throw(::com::sun::star::uno::RuntimeException)
769 {
770 	OGuard aGuard( Application::GetSolarMutex() );
771 	return mpPropSet->getPropertySetInfo();
772 }
773 
774 void SAL_CALL SdUnoSearchReplaceDescriptor::setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue )
775 	throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
776 {
777 	OGuard aGuard( Application::GetSolarMutex() );
778 
779 	const SfxItemPropertySimpleEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName);
780 
781 	sal_Bool bOk = sal_False;
782 
783 	switch( pEntry ? pEntry->nWID : -1 )
784 	{
785 	case WID_SEARCH_BACKWARDS:
786 		bOk = (aValue >>= mbBackwards);
787 		break;
788 	case WID_SEARCH_CASE:
789 		bOk = (aValue >>= mbCaseSensitive);
790 		break;
791 	case WID_SEARCH_WORDS:
792 		bOk = (aValue >>= mbWords);
793 		break;
794 	default:
795 		throw beans::UnknownPropertyException();
796 	}
797 
798 	if( !bOk )
799 		throw lang::IllegalArgumentException();
800 }
801 
802 uno::Any SAL_CALL SdUnoSearchReplaceDescriptor::getPropertyValue( const ::rtl::OUString& PropertyName )
803 	throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
804 {
805 	OGuard aGuard( Application::GetSolarMutex() );
806 
807 	uno::Any aAny;
808 
809 	const SfxItemPropertySimpleEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName);
810 
811 	switch( pEntry ? pEntry->nWID : -1 )
812 	{
813 	case WID_SEARCH_BACKWARDS:
814 		aAny <<= (sal_Bool)mbBackwards;
815 		break;
816 	case WID_SEARCH_CASE:
817 		aAny <<= (sal_Bool)mbCaseSensitive;
818 		break;
819 	case WID_SEARCH_WORDS:
820 		aAny <<= (sal_Bool)mbWords;
821 		break;
822 	default:
823 		throw beans::UnknownPropertyException();
824 	}
825 
826 	return aAny;
827 }
828 
829 void SAL_CALL SdUnoSearchReplaceDescriptor::addPropertyChangeListener( const ::rtl::OUString& , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >&  ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) {}
830 void SAL_CALL SdUnoSearchReplaceDescriptor::removePropertyChangeListener( const ::rtl::OUString& , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >&  ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) {}
831 void SAL_CALL SdUnoSearchReplaceDescriptor::addVetoableChangeListener( const ::rtl::OUString& , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >&  ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) {}
832 void SAL_CALL SdUnoSearchReplaceDescriptor::removeVetoableChangeListener( const ::rtl::OUString& , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >&  ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) {}
833 
834 
835 /* ================================================================= */
836 
837 SdUnoFindAllAccess::SdUnoFindAllAccess( uno::Sequence< uno::Reference< uno::XInterface >  >& rSequence ) throw()
838 :maSequence( rSequence )
839 {
840 }
841 
842 SdUnoFindAllAccess::~SdUnoFindAllAccess() throw()
843 {
844 }
845 
846 // XElementAccess
847 uno::Type SAL_CALL SdUnoFindAllAccess::getElementType()
848 	throw(::com::sun::star::uno::RuntimeException)
849 {
850 	return ITYPE( text::XTextRange );
851 }
852 
853 sal_Bool SAL_CALL SdUnoFindAllAccess::hasElements()
854 	throw(::com::sun::star::uno::RuntimeException)
855 {
856 	return maSequence.getLength() > 0;
857 }
858 
859 // XIndexAccess
860 sal_Int32 SAL_CALL SdUnoFindAllAccess::getCount()
861 	throw(::com::sun::star::uno::RuntimeException)
862 {
863 	return maSequence.getLength();
864 }
865 
866 uno::Any SAL_CALL SdUnoFindAllAccess::getByIndex( sal_Int32 Index )
867 	throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
868 {
869 	uno::Any aAny;
870 
871 	if( Index < 0 || Index >= getCount() )
872 		throw lang::IndexOutOfBoundsException();
873 
874 	const uno::Reference< uno::XInterface >  *pRefs = maSequence.getConstArray();
875 	if(pRefs)
876 		aAny <<= pRefs[ Index ];
877 	return aAny;
878 }
879 
880