xref: /trunk/main/sd/source/ui/unoidl/unosrch.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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