xref: /trunk/main/sw/source/core/crsr/findattr.cxx (revision 30acf5e801d38c3701bf451b42e514ce81855b4c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <com/sun/star/lang/Locale.hpp>
29 #include <com/sun/star/util/SearchOptions.hpp>
30 #include <com/sun/star/util/SearchFlags.hpp>
31 #include <i18npool/mslangid.hxx>
32 #include <hintids.hxx>
33 #include <vcl/svapp.hxx>
34 #include <svl/itemiter.hxx>
35 #include <svl/whiter.hxx>
36 #include <editeng/brkitem.hxx>
37 #include <editeng/colritem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <fmtpdsc.hxx>
40 #include <txatbase.hxx>
41 #include <fchrfmt.hxx>
42 #include <charfmt.hxx>
43 #include <doc.hxx>
44 #include <IDocumentUndoRedo.hxx>
45 #include <swcrsr.hxx>
46 #include <editsh.hxx>
47 #include <ndtxt.hxx>
48 #include <pamtyp.hxx>
49 #include <swundo.hxx>
50 #include <crsskip.hxx>
51 
52 
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::lang;
55 using namespace ::com::sun::star::util;
56 
57 SV_DECL_PTRARR_SORT( SwpFmts, SwFmt*, 0, 4 )
58 SV_IMPL_PTRARR_SORT( SwpFmts, SwFmt* )
59 
60     // Sonderbehandlung fuer SvxFontItem, nur den Namen vergleichen:
61 int CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 )
62 {
63     switch( rItem1.Which() )
64     {
65     case RES_CHRATR_FONT:
66         return ((SvxFontItem&)rItem1).GetFamilyName() ==
67                 ((SvxFontItem&)rItem2).GetFamilyName();
68 
69     case RES_CHRATR_COLOR:
70         return ((SvxColorItem&)rItem1).GetValue().IsRGBEqual(
71                                 ((SvxColorItem&)rItem2).GetValue() );
72     case RES_PAGEDESC:
73         return ((SwFmtPageDesc&)rItem1).GetNumOffset() ==
74                         ((SwFmtPageDesc&)rItem2).GetNumOffset() &&
75                 ((SwFmtPageDesc&)rItem1).GetPageDesc() ==
76                         ((SwFmtPageDesc&)rItem2).GetPageDesc();
77     }
78     return rItem1 == rItem2;
79 }
80 
81 
82 const SwTxtAttr* GetFrwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
83                                     xub_StrLen nCntntPos )
84 {
85     while( rPos < rHtsArr.Count() )
86     {
87         const SwTxtAttr *pTxtHt = rHtsArr.GetStart( rPos++ );
88         // der Start vom Attribut muss innerhalb des Bereiches liegen !!
89         if( *pTxtHt->GetStart() >= nCntntPos )
90             return pTxtHt;      // gueltiges TextAttribut
91     }
92     return 0;                   // kein gueltiges TextAttribut
93 }
94 
95 
96 const SwTxtAttr* GetBkwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
97                                   xub_StrLen nCntntPos )
98 {
99     while( rPos > 0 )
100     {
101         //Hack mit cast fuer das Update
102         const SwTxtAttr *pTxtHt = rHtsArr.GetStart( --rPos );
103         // der Start vom Attribut muss innerhalb des Bereiches liegen !!
104         if( *pTxtHt->GetStart() < nCntntPos )
105             return pTxtHt;      // gueltiges TextAttribut
106     }
107     return 0;                   // kein gueltiges TextAttribut
108 }
109 
110 
111 void lcl_SetAttrPam( SwPaM & rPam, xub_StrLen nStart, const xub_StrLen* pEnde,
112                         const sal_Bool bSaveMark )
113 {
114     xub_StrLen nCntntPos;
115     if( bSaveMark )
116         nCntntPos = rPam.GetMark()->nContent.GetIndex();
117     else
118         nCntntPos = rPam.GetPoint()->nContent.GetIndex();
119     sal_Bool bTstEnde = rPam.GetPoint()->nNode == rPam.GetMark()->nNode;
120 
121     SwCntntNode* pCNd = rPam.GetCntntNode();
122     rPam.GetPoint()->nContent.Assign( pCNd, nStart );
123     rPam.SetMark();     // Point == GetMark
124 
125     // Point zeigt auf das Ende vom SuchBereich oder Ende vom Attribut
126     if( pEnde )
127     {
128         if( bTstEnde && *pEnde > nCntntPos )
129             rPam.GetPoint()->nContent = nCntntPos;
130         else
131             rPam.GetPoint()->nContent = *pEnde;
132     }
133 }
134 
135 //------------------ Suche nach einem Text Attribut -----------------------
136 
137 // diese Funktion sucht in einem TextNode nach dem vorgegebenen Attribut.
138 // Wird es gefunden, dann hat der SwPaM den Bereich der das Attribut
139 // umspannt, unter Beachtung des Suchbereiches
140 
141 
142 sal_Bool lcl_Search( const SwTxtNode& rTxtNd, SwPaM& rPam,
143                     const SfxPoolItem& rCmpItem,
144                     SwMoveFn fnMove, sal_Bool bValue )
145 {
146     if ( !rTxtNd.HasHints() )
147         return sal_False;
148     const SwTxtAttr *pTxtHt = 0;
149     sal_Bool bForward = fnMove == fnMoveForward;
150     sal_uInt16 nPos = bForward ? 0 : rTxtNd.GetSwpHints().Count();
151     xub_StrLen nCntntPos = rPam.GetPoint()->nContent.GetIndex();
152 
153     while( 0 != ( pTxtHt=(*fnMove->fnGetHint)(rTxtNd.GetSwpHints(),nPos,nCntntPos)))
154         if( pTxtHt->Which() == rCmpItem.Which() &&
155             ( !bValue || CmpAttr( pTxtHt->GetAttr(), rCmpItem )))
156         {
157             lcl_SetAttrPam( rPam, *pTxtHt->GetStart(), pTxtHt->End(), bForward );
158             return sal_True;
159         }
160     return sal_False;
161 }
162 
163 
164 //------------------ Suche nach mehren Text Attributen -------------------
165 
166 struct _SwSrchChrAttr
167 {
168     sal_uInt16 nWhich;
169     xub_StrLen nStt, nEnd;
170 
171     _SwSrchChrAttr( const SfxPoolItem& rItem,
172                     xub_StrLen nStart, xub_StrLen nAnyEnd )
173         : nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd )
174     {}
175 };
176 
177 class SwAttrCheckArr
178 {
179     _SwSrchChrAttr *pFndArr, *pStackArr;
180     xub_StrLen nNdStt, nNdEnd;
181     sal_uInt16 nArrStart, nArrLen;
182     sal_uInt16 nFound, nStackCnt;
183     SfxItemSet aCmpSet;
184     sal_Bool bNoColls;
185     sal_Bool bForward;
186 
187 public:
188     SwAttrCheckArr( const SfxItemSet& rSet, int bForward, int bNoCollections );
189     ~SwAttrCheckArr();
190 
191     void SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam );
192 
193     // wieviele Attribute ueberhaupt ??
194     sal_uInt16 Count() const    { return aCmpSet.Count(); }
195     int Found() const       { return nFound == aCmpSet.Count(); }
196     int CheckStack();
197 
198     xub_StrLen Start() const;
199     xub_StrLen End() const;
200 
201     xub_StrLen GetNdStt() const { return nNdStt; }
202     xub_StrLen GetNdEnd() const { return nNdEnd; }
203 
204     int SetAttrFwd( const SwTxtAttr& rAttr );
205     int SetAttrBwd( const SwTxtAttr& rAttr );
206 };
207 
208 
209 
210 SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet& rSet, int bFwd,
211                                 int bNoCollections )
212     : aCmpSet( *rSet.GetPool(), RES_CHRATR_BEGIN, RES_TXTATR_END-1 )
213 {
214     aCmpSet.Put( rSet, sal_False );
215     bNoColls = 0 != bNoCollections;
216 
217     bForward = 0 != bFwd;
218 
219     // Bestimmen den Bereich des Fnd/Stack-Arrays (Min/Max)
220     SfxItemIter aIter( aCmpSet );
221     nArrStart = aCmpSet.GetWhichByPos( aIter.GetFirstPos() );
222     nArrLen = aCmpSet.GetWhichByPos( aIter.GetLastPos() ) - nArrStart+1;
223 
224     char* pFndChar  = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
225     char* pStackChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
226 
227     pFndArr = (_SwSrchChrAttr*)pFndChar;
228     pStackArr = (_SwSrchChrAttr*)pStackChar;
229 }
230 
231 SwAttrCheckArr::~SwAttrCheckArr()
232 {
233     delete[] (char*)pFndArr;
234     delete[] (char*)pStackArr;
235 }
236 
237 void SwAttrCheckArr::SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam )
238 {
239     memset( pFndArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
240     memset( pStackArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
241     nFound = 0;
242     nStackCnt = 0;
243 
244     if( bForward )
245     {
246         nNdStt = rPam.GetPoint()->nContent.GetIndex();
247         nNdEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
248                 ? rPam.GetMark()->nContent.GetIndex()
249                 : rTxtNd.GetTxt().Len();
250     }
251     else
252     {
253         nNdEnd = rPam.GetPoint()->nContent.GetIndex();
254         nNdStt = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
255                 ? rPam.GetMark()->nContent.GetIndex()
256                 : 0;
257     }
258 
259     if( bNoColls && !rTxtNd.HasSwAttrSet() )
260         return ;
261 
262     const SfxItemSet& rSet = rTxtNd.GetSwAttrSet();
263 //  if( !rSet.Count() )
264 //      return;
265 
266     SfxItemIter aIter( aCmpSet );
267     const SfxPoolItem* pItem = aIter.GetCurItem();
268     const SfxPoolItem* pFndItem;
269     sal_uInt16 nWhich;
270 
271     while( sal_True )
272     {
273         // nur testen, ob vorhanden ist ?
274         if( IsInvalidItem( pItem ) )
275         {
276             nWhich = aCmpSet.GetWhichByPos( aIter.GetCurPos() );
277             if( RES_TXTATR_END <= nWhich )
278                 break;              // Ende der TextAttribute
279 
280             if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
281                 && !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) ))
282             {
283                 pFndArr[ nWhich - nArrStart ] =
284                     _SwSrchChrAttr( *pFndItem, nNdStt, nNdEnd );
285                 nFound++;
286             }
287         }
288         else
289         {
290             if( RES_TXTATR_END <= (nWhich = pItem->Which() ))
291                 break;              // Ende der TextAttribute
292 
293 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
294 //              runter
295 //          if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
296 //                && *pFndItem == *pItem )
297             if( CmpAttr( rSet.Get( nWhich, !bNoColls ), *pItem ) )
298             {
299                 pFndArr[ nWhich - nArrStart ] =
300                     _SwSrchChrAttr( *pItem, nNdStt, nNdEnd );
301                 nFound++;
302             }
303         }
304 
305         if( aIter.IsAtEnd() )
306             break;
307         pItem = aIter.NextItem();
308     }
309 }
310 
311 static bool
312 lcl_IsAttributeIgnorable(xub_StrLen const nNdStart, xub_StrLen const nNdEnd,
313         _SwSrchChrAttr const& rTmp)
314 {
315     // #i115528#: if there is a paragraph attribute, it has been added by the
316     // SwAttrCheckArr ctor, and nFound is 1.
317     // if the paragraph is entirely covered by hints that override the paragraph
318     // attribute, then this function must find an attribute to decrement nFound!
319     // so check for an empty search range, let attributes that start/end there
320     // cover it, and hope for the best...
321     return ((nNdEnd == nNdStart)
322             ? ((rTmp.nEnd <  nNdStart) || (nNdEnd <  rTmp.nStt))
323             : ((rTmp.nEnd <= nNdStart) || (nNdEnd <= rTmp.nStt)));
324 }
325 
326 int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr& rAttr )
327 {
328     _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
329 
330     // ignore all attributes not in search range
331     if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
332     {
333         return Found();
334     }
335 
336     const SfxPoolItem* pItem;
337 // --------------------------------------------------------------
338 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
339 // --------------------------------------------------------------
340     sal_uInt16 nWhch = rAttr.Which();
341     SfxWhichIter* pIter = NULL;
342     const SfxPoolItem* pTmpItem = NULL;
343     const SfxItemSet* pSet = NULL;
344     if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
345     {
346         if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
347             return Found();
348         pTmpItem = NULL;
349         pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
350         if ( pSet )
351         {
352             pIter = new SfxWhichIter( *pSet );
353             nWhch = pIter->FirstWhich();
354             while( nWhch &&
355                 SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
356                 nWhch = pIter->NextWhich();
357             if( !nWhch )
358                 pTmpItem = NULL;
359         }
360     }
361     else
362         pTmpItem = &rAttr.GetAttr();
363     while( pTmpItem )
364     {
365         SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
366         if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
367         {
368             sal_uInt16 n;
369             _SwSrchChrAttr* pCmp;
370 
371             // loesche erstmal alle, die bis zu der Start Position schon wieder
372             // ungueltig sind:
373 
374             _SwSrchChrAttr* pArrPtr;
375             if( nFound )
376                 for( pArrPtr = pFndArr, n = 0; n < nArrLen;
377                     ++n, ++pArrPtr )
378                     if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt )
379                     {
380                         pArrPtr->nWhich = 0;        // geloescht
381                         nFound--;
382                     }
383 
384             // loesche erstmal alle, die bis zu der Start Position schon wieder
385             // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
386             // die Start Position ragen, vom Stack in den FndSet
387 
388             if( nStackCnt )
389                 for( pArrPtr = pStackArr, n=0; n < nArrLen; ++n, ++pArrPtr )
390                 {
391                     if( !pArrPtr->nWhich )
392                         continue;
393 
394                     if( pArrPtr->nEnd <= aTmp.nStt )
395                     {
396                         pArrPtr->nWhich = 0;        // geloescht
397                         if( !--nStackCnt )
398                             break;
399                     }
400                     else if( pArrPtr->nStt <= aTmp.nStt )
401                     {
402                         if( ( pCmp = &pFndArr[ n ])->nWhich )
403                         {
404                             if( pCmp->nEnd < pArrPtr->nEnd )        // erweitern
405                                 pCmp->nEnd = pArrPtr->nEnd;
406                         }
407                         else
408                         {
409                             *pCmp = *pArrPtr;
410                             nFound++;
411                         }
412                         pArrPtr->nWhich = 0;
413                         if( !--nStackCnt )
414                             break;
415                     }
416                 }
417 
418             sal_Bool bContinue = sal_False;
419 
420             if( SFX_ITEM_DONTCARE == eState  )
421             {
422                 // wird Attribut gueltig ?
423                 if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
424                     *pTmpItem ))
425                 {
426                     // suche das Attribut und erweiter es gegebenenfalls
427                     if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
428                     {
429                         *pCmp = aTmp;               // nicht gefunden, eintragen
430                         nFound++;
431                     }
432                     else if( pCmp->nEnd < aTmp.nEnd )       // erweitern ?
433                         pCmp->nEnd = aTmp.nEnd;
434 
435                     bContinue = sal_True;
436                 }
437             }
438             // wird Attribut gueltig ?
439             else if(  CmpAttr( *pItem, *pTmpItem ) )
440             {
441                 pFndArr[ nWhch - nArrStart ] = aTmp;
442                 ++nFound;
443                 bContinue = sal_True;
444             }
445 
446             // tja, dann muss es auf den Stack
447             if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
448             {
449                 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
450                 if( pCmp->nEnd > aTmp.nEnd )
451                 {
452                     ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich,
453                                     "Stack-Platz ist noch belegt" );
454 
455         // ---------
456         // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
457         //          pCmp->nStt = aTmp.nEnd;
458                     if( aTmp.nStt <= pCmp->nStt )
459                         pCmp->nStt = aTmp.nEnd;
460                     else
461                         pCmp->nEnd = aTmp.nStt;
462         // ---------
463 
464                     pStackArr[ nWhch - nArrStart ] = *pCmp;
465                     nStackCnt++;
466                 }
467                 pCmp->nWhich = 0;
468                 nFound--;
469             }
470         }
471         if( pIter )
472         {
473             nWhch = pIter->NextWhich();
474             while( nWhch &&
475                 SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
476                 nWhch = pIter->NextWhich();
477             if( !nWhch )
478                 break;
479         }
480         else
481             break;
482     }
483     delete pIter;
484     return Found();
485 }
486 
487 
488 int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr& rAttr )
489 {
490     _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
491 
492     // ignore all attributes not in search range
493     if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
494     {
495         return Found();
496     }
497 
498     const SfxPoolItem* pItem;
499 // --------------------------------------------------------------
500 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
501 // --------------------------------------------------------------
502     sal_uInt16 nWhch = rAttr.Which();
503     SfxWhichIter* pIter = NULL;
504     const SfxPoolItem* pTmpItem = NULL;
505     const SfxItemSet* pSet = NULL;
506     if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
507     {
508         if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
509             return Found();
510 
511         pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
512         if ( pSet )
513         {
514             pIter = new SfxWhichIter( *pSet );
515             nWhch = pIter->FirstWhich();
516             while( nWhch &&
517                 SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
518                 nWhch = pIter->NextWhich();
519             if( !nWhch )
520                 pTmpItem = NULL;
521         }
522     }
523     else
524         pTmpItem = &rAttr.GetAttr();
525     while( pTmpItem )
526     {
527         SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
528         if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
529         {
530             sal_uInt16 n;
531             _SwSrchChrAttr* pCmp;
532 
533             // loesche erstmal alle, die bis zu der Start Position schon wieder
534             // ungueltig sind:
535 
536             _SwSrchChrAttr* pArrPtr;
537             if( nFound )
538                 for( pArrPtr = pFndArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
539                     if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd )
540                     {
541                         pArrPtr->nWhich = 0;        // geloescht
542                         nFound--;
543                     }
544 
545             // loesche erstmal alle, die bis zu der Start Position schon wieder
546             // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
547             // die Start Position ragen, vom Stack in den FndSet
548 
549             if( nStackCnt )
550                 for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
551                 {
552                     if( !pArrPtr->nWhich )
553                         continue;
554 
555                     if( pArrPtr->nStt >= aTmp.nEnd )
556                     {
557                         pArrPtr->nWhich = 0;        // geloescht
558                         if( !--nStackCnt )
559                             break;
560                     }
561                     else if( pArrPtr->nEnd >= aTmp.nEnd )
562                     {
563                         if( ( pCmp = &pFndArr[ n ])->nWhich )
564                         {
565                             if( pCmp->nStt > pArrPtr->nStt )        // erweitern
566                                 pCmp->nStt = pArrPtr->nStt;
567                         }
568                         else
569                         {
570                             *pCmp = *pArrPtr;
571                             nFound++;
572                     }
573                     pArrPtr->nWhich = 0;
574                     if( !--nStackCnt )
575                         break;
576                 }
577             }
578 
579             sal_Bool bContinue = sal_False;
580             if( SFX_ITEM_DONTCARE == eState  )
581             {
582                 // wird Attribut gueltig ?
583                 if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
584                     *pTmpItem ) )
585                 {
586                     // suche das Attribut und erweiter es gegebenenfalls
587                     if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
588                     {
589                         *pCmp = aTmp;               // nicht gefunden, eintragen
590                         nFound++;
591                     }
592                     else if( pCmp->nStt > aTmp.nStt )       // erweitern ?
593                         pCmp->nStt = aTmp.nStt;
594 
595                     bContinue = sal_True;
596                 }
597             }
598             // wird Attribut gueltig ?
599             else if( CmpAttr( *pItem, *pTmpItem ))
600             {
601                 pFndArr[ nWhch - nArrStart ] = aTmp;
602                 ++nFound;
603                 bContinue = sal_True;
604             }
605 
606             // tja, dann muss es auf den Stack
607             if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
608             {
609                 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
610                 if( pCmp->nStt < aTmp.nStt )
611                 {
612                     ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich,
613                             "Stack-Platz ist noch belegt" );
614 
615 // ---------
616 // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
617 //          pCmp->nEnd = aTmp.nStt;
618                     if( aTmp.nEnd <= pCmp->nEnd )
619                         pCmp->nEnd = aTmp.nStt;
620                     else
621                         pCmp->nStt = aTmp.nEnd;
622 // ---------
623 
624                     pStackArr[ nWhch - nArrStart ] = *pCmp;
625                     nStackCnt++;
626                 }
627                 pCmp->nWhich = 0;
628                 nFound--;
629             }
630         }
631         if( pIter )
632         {
633             nWhch = pIter->NextWhich();
634             while( nWhch &&
635                 SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
636                 nWhch = pIter->NextWhich();
637             if( !nWhch )
638                 break;
639         }
640         else
641             break;
642     }
643     delete pIter;
644     return Found();
645 }
646 
647 
648 xub_StrLen SwAttrCheckArr::Start() const
649 {
650     xub_StrLen nStart = nNdStt;
651     _SwSrchChrAttr* pArrPtr = pFndArr;
652     for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
653         if( pArrPtr->nWhich && pArrPtr->nStt > nStart )
654             nStart = pArrPtr->nStt;
655 
656     return nStart;
657 }
658 
659 
660 xub_StrLen SwAttrCheckArr::End() const
661 {
662     _SwSrchChrAttr* pArrPtr = pFndArr;
663     xub_StrLen nEnd = nNdEnd;
664     for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
665         if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd )
666             nEnd = pArrPtr->nEnd;
667 
668     return nEnd;
669 }
670 
671 
672 int SwAttrCheckArr::CheckStack()
673 {
674     if( !nStackCnt )
675         return sal_False;
676 
677     sal_uInt16 n;
678     xub_StrLen nSttPos = Start(), nEndPos = End();
679     _SwSrchChrAttr* pArrPtr;
680     for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
681     {
682         if( !pArrPtr->nWhich )
683             continue;
684 
685         if( bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos )
686         {
687             pArrPtr->nWhich = 0;        // geloescht
688             if( !--nStackCnt )
689                 return nFound == aCmpSet.Count();
690         }
691         else if( bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos )
692         {
693             // alle die "offen" sind, heisst ueber die Start Position ragen,
694             // im FndSet setzen
695             ASSERT( !pFndArr[ n ].nWhich, "Array-Platz ist noch belegt" );
696             pFndArr[ n ] = *pArrPtr;
697             pArrPtr->nWhich = 0;
698             nFound++;
699             if( !--nStackCnt )
700                 return nFound == aCmpSet.Count();
701         }
702     }
703     return nFound == aCmpSet.Count();
704 }
705 
706 
707 
708 int lcl_SearchForward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
709                             SwPaM& rPam )
710 {
711     xub_StrLen nEndPos, nSttPos;
712     rCmpArr.SetNewSet( rTxtNd, rPam );
713     if( !rTxtNd.HasHints() )
714     {
715         if( !rCmpArr.Found() )
716             return sal_False;
717         nEndPos = rCmpArr.GetNdEnd();
718         lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
719         return sal_True;
720     }
721 
722     // dann gehe mal durch das nach "Start" sortierte Array
723     const SwpHints& rHtArr = rTxtNd.GetSwpHints();
724     const SwTxtAttr* pAttr;
725     sal_uInt16 nPos = 0;
726 
727     // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
728     // das wieder beendet wird.
729     if( rCmpArr.Found() )
730     {
731         for( ; nPos < rHtArr.Count(); ++nPos )
732             if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
733             {
734                 if( rCmpArr.GetNdStt() < *pAttr->GetStart() )
735                 {
736                     // dann haben wir unser Ende:
737                     lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
738                                 pAttr->GetStart(), sal_True );
739                     return sal_True;
740                 }
741                 // ansonsten muessen wir weiter suchen
742                 break;
743             }
744 
745         if( nPos == rHtArr.Count() && rCmpArr.Found() )
746         {
747             // dann haben wir unseren Bereich
748             nEndPos = rCmpArr.GetNdEnd();
749             lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
750             return sal_True;
751         }
752     }
753 
754     for( ; nPos < rHtArr.Count(); ++nPos )
755         if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
756         {
757             // sollten noch mehr auf der gleichen Position anfangen ??
758             // auch die noch mit testen !!
759             nSttPos = *pAttr->GetStart();
760             while( ++nPos < rHtArr.Count() && nSttPos ==
761                     *( pAttr = rHtArr.GetStart( nPos ))->GetStart() &&
762                     rCmpArr.SetAttrFwd( *pAttr ) )
763                 ;
764             if( !rCmpArr.Found() )
765                 continue;
766 
767             // dann haben wir den Bereich zusammen
768             if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
769                 return sal_False;
770             lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
771             return sal_True;
772         }
773 
774     if( !rCmpArr.CheckStack() ||
775         (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
776         return sal_False;
777     lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
778     return sal_True;
779 }
780 
781 
782 int lcl_SearchBackward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
783                             SwPaM& rPam )
784 {
785     xub_StrLen nEndPos, nSttPos;
786     rCmpArr.SetNewSet( rTxtNd, rPam );
787     if( !rTxtNd.HasHints() )
788     {
789         if( !rCmpArr.Found() )
790             return sal_False;
791         nEndPos = rCmpArr.GetNdEnd();
792         lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
793         return sal_True;
794     }
795 
796     // dann gehe mal durch das nach "Start" sortierte Array
797     const SwpHints& rHtArr = rTxtNd.GetSwpHints();
798     const SwTxtAttr* pAttr;
799     sal_uInt16 nPos = rHtArr.Count();
800 
801     // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
802     // das wieder beendet wird.
803     if( rCmpArr.Found() )
804     {
805         while( nPos )
806             if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
807             {
808                 nSttPos = *pAttr->GetAnyEnd();
809                 if( nSttPos < rCmpArr.GetNdEnd() )
810                 {
811                     // dann haben wir unser Ende:
812                     nEndPos = rCmpArr.GetNdEnd();
813                     lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
814                     return sal_True;
815                 }
816 
817                 // ansonsten muessen wir weiter suchen
818                 break;
819             }
820 
821         if( !nPos && rCmpArr.Found() )
822         {
823             // dann haben wir unseren Bereich
824             nEndPos = rCmpArr.GetNdEnd();
825             lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
826             return sal_True;
827         }
828     }
829 
830     while( nPos )
831         if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
832         {
833             // sollten noch mehr auf der gleichen Position anfangen ??
834             // auch die noch mit testen !!
835             if( nPos )
836             {
837                 nEndPos = *pAttr->GetAnyEnd();
838                 while( --nPos && nEndPos ==
839                         *( pAttr = rHtArr.GetEnd( nPos ))->GetAnyEnd() &&
840                         rCmpArr.SetAttrBwd( *pAttr ) )
841                     ;
842             }
843             if( !rCmpArr.Found() )
844                 continue;
845 
846 
847             // dann haben wir den Bereich zusammen
848             if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
849                 return sal_False;
850             lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
851             return sal_True;
852         }
853 
854     if( !rCmpArr.CheckStack() ||
855         (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
856         return sal_False;
857     lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
858     return sal_True;
859 }
860 
861 
862 int lcl_Search( const SwCntntNode& rCNd, const SfxItemSet& rCmpSet, sal_Bool bNoColls )
863 {
864     // nur die harte Attributierung suchen ?
865     if( bNoColls && !rCNd.HasSwAttrSet() )
866         return sal_False;
867 
868     const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
869     SfxItemIter aIter( rCmpSet );
870     const SfxPoolItem* pItem = aIter.GetCurItem();
871     const SfxPoolItem* pNdItem;
872     sal_uInt16 nWhich;
873 
874     while( sal_True )
875     {
876         // nur testen, ob vorhanden ist ?
877         if( IsInvalidItem( pItem ))
878         {
879             nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
880             if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
881                 || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
882                 return sal_False;
883         }
884         else
885         {
886             nWhich = pItem->Which();
887 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
888 //              runter
889 //          if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
890 //              || *pNdItem != *pItem )
891             if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
892                 return sal_False;
893         }
894 
895         if( aIter.IsAtEnd() )
896             break;
897         pItem = aIter.NextItem();
898     }
899     return sal_True;            // wurde gefunden
900 }
901 
902 
903 sal_Bool SwPaM::Find( const SfxPoolItem& rAttr, sal_Bool bValue, SwMoveFn fnMove,
904                     const SwPaM *pRegion, sal_Bool bInReadOnly )
905 {
906     // stelle fest welches Attribut gesucht wird:
907     const sal_uInt16 nWhich = rAttr.Which();
908     int bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
909 
910     SwPaM* pPam = MakeRegion( fnMove, pRegion );
911 
912     sal_Bool bFound = sal_False;
913     sal_Bool bFirst = sal_True;
914     sal_Bool bSrchForward = fnMove == fnMoveForward;
915     SwCntntNode * pNode;
916     const SfxPoolItem* pItem;
917     SwpFmts aFmtArr;
918 
919     // Wenn am Anfang/Ende, aus dem Node moven
920     if( bSrchForward
921         ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
922         : !pPam->GetPoint()->nContent.GetIndex() )
923     {
924         if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
925         {
926             delete pPam;
927             return sal_False;
928         }
929         SwCntntNode *pNd = pPam->GetCntntNode();
930         xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
931         pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
932     }
933 
934     while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
935     {
936         if( bCharAttr )
937         {
938             if( !pNode->IsTxtNode() )       // CharAttr sind nur in TextNodes
939                 continue;
940 
941             if( ((SwTxtNode*)pNode)->HasHints() &&
942                 lcl_Search( *(SwTxtNode*)pNode, *pPam, rAttr, fnMove,  bValue ))
943             {
944                 // setze auf die Werte vom Attribut
945                 SetMark();
946                 *GetPoint() = *pPam->GetPoint();
947                 *GetMark() = *pPam->GetMark();
948                 bFound = sal_True;
949                 break;
950             }
951             else if (isTXTATR(nWhich))
952                 continue;               // --> also weiter
953         }
954 
955         // keine harte Attributierung, dann pruefe, ob die Vorlage schon
956         // mal nach dem Attribut befragt wurde
957         if( !pNode->HasSwAttrSet() )
958         {
959             const SwFmt* pTmpFmt = pNode->GetFmtColl();
960             if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
961                 continue;   // die Collection wurde schon mal befragt
962             aFmtArr.Insert( pTmpFmt );
963         }
964 
965         if( SFX_ITEM_SET == pNode->GetSwAttrSet().GetItemState( nWhich,
966             sal_True, &pItem ) && ( !bValue || *pItem == rAttr ) )
967         {
968             // FORWARD:  Point an das Ende, GetMark zum Anfanf vom Node
969             // BACKWARD: Point zum Anfang,  GetMark an das Ende vom Node
970             // und immer nach der Logik: inkl. Start, exkl. End !!!
971             *GetPoint() = *pPam->GetPoint();
972             SetMark();
973             pNode->MakeEndIndex( &GetPoint()->nContent );
974             bFound = sal_True;
975             break;
976         }
977     }
978 
979     // beim rueckwaerts Suchen noch Point und Mark vertauschen
980     if( bFound && !bSrchForward )
981         Exchange();
982 
983     delete pPam;
984     return bFound;
985 }
986 
987 
988 typedef int (*FnSearchAttr)( const SwTxtNode&, SwAttrCheckArr&, SwPaM& );
989 
990 sal_Bool SwPaM::Find( const SfxItemSet& rSet, sal_Bool bNoColls, SwMoveFn fnMove,
991                     const SwPaM *pRegion, sal_Bool bInReadOnly, sal_Bool bMoveFirst )
992 {
993     SwPaM* pPam = MakeRegion( fnMove, pRegion );
994 
995     sal_Bool bFound = sal_False;
996     sal_Bool bFirst = sal_True;
997     sal_Bool bSrchForward = fnMove == fnMoveForward;
998     SwCntntNode * pNode;
999     SwpFmts aFmtArr;
1000 
1001     // teste doch mal welche Text/Char-Attribute gesucht werden
1002     SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
1003     SfxItemSet aOtherSet( GetDoc()->GetAttrPool(),
1004                             RES_PARATR_BEGIN, RES_GRFATR_END-1 );
1005     aOtherSet.Put( rSet, sal_False );   // alle Invalid-Items erhalten!
1006 
1007     FnSearchAttr fnSearch = bSrchForward
1008                                 ? (&::lcl_SearchForward)
1009                                 : (&::lcl_SearchBackward);
1010 
1011     // Wenn am Anfang/Ende, aus dem Node moven
1012     // Wenn am Anfang/Ende, aus dem Node moven
1013     if( bMoveFirst &&
1014         ( bSrchForward
1015         ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
1016         : !pPam->GetPoint()->nContent.GetIndex() ) )
1017     {
1018         if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
1019         {
1020             delete pPam;
1021             return sal_False;
1022         }
1023         SwCntntNode *pNd = pPam->GetCntntNode();
1024         xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
1025         pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
1026     }
1027 
1028 
1029     while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
1030     {
1031         if( aCmpArr.Count() )
1032         {
1033             if( !pNode->IsTxtNode() )       // CharAttr sind nur in TextNodes
1034                 continue;
1035 
1036             if( (!aOtherSet.Count() ||
1037                 lcl_Search( *pNode, aOtherSet, bNoColls )) &&
1038                 (*fnSearch)( *(SwTxtNode*)pNode, aCmpArr, *pPam ))
1039             {
1040                 // setze auf die Werte vom Attribut
1041                 SetMark();
1042                 *GetPoint() = *pPam->GetPoint();
1043                 *GetMark() = *pPam->GetMark();
1044                 bFound = sal_True;
1045                 break;
1046             }
1047             continue;       // TextAttribute
1048         }
1049 
1050         if( !aOtherSet.Count() )
1051             continue;
1052 
1053         // keine harte Attributierung, dann pruefe, ob die Vorlage schon
1054         // mal nach dem Attribut befragt wurde
1055         if( !pNode->HasSwAttrSet() )
1056         {
1057             const SwFmt* pTmpFmt = pNode->GetFmtColl();
1058             if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
1059                 continue;   // die Collection wurde schon mal befragt
1060             aFmtArr.Insert( pTmpFmt );
1061         }
1062 
1063         if( lcl_Search( *pNode, aOtherSet, bNoColls ))
1064         {
1065             // FORWARD:  Point an das Ende, GetMark zum Anfanf vom Node
1066             // BACKWARD: Point zum Anfang,  GetMark an das Ende vom Node
1067             // und immer nach der Logik: inkl. Start, exkl. End !!!
1068             *GetPoint() = *pPam->GetPoint();
1069             SetMark();
1070             pNode->MakeEndIndex( &GetPoint()->nContent );
1071             bFound = sal_True;
1072             break;
1073         }
1074     }
1075 
1076     // beim rueckwaerts Suchen noch Point und Mark vertauschen
1077     if( bFound && !bSrchForward )
1078         Exchange();
1079 
1080     delete pPam;
1081     return bFound;
1082 }
1083 
1084 //------------------ Methoden vom SwCursor ---------------------------
1085 
1086 // Parameter fuer das Suchen vom Attributen
1087 struct SwFindParaAttr : public SwFindParas
1088 {
1089     sal_Bool bValue;
1090     const SfxItemSet *pSet, *pReplSet;
1091     const SearchOptions *pSearchOpt;
1092     SwCursor& rCursor;
1093     utl::TextSearch* pSTxt;
1094 
1095     SwFindParaAttr( const SfxItemSet& rSet, sal_Bool bNoCollection,
1096                     const SearchOptions* pOpt, const SfxItemSet* pRSet,
1097                     SwCursor& rCrsr )
1098         : bValue( bNoCollection ), pSet( &rSet ), pReplSet( pRSet ),
1099           pSearchOpt( pOpt ), rCursor( rCrsr ),pSTxt( 0 ) {}
1100 
1101     virtual ~SwFindParaAttr()   { delete pSTxt; }
1102 
1103     virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
1104     virtual int IsReplaceMode() const;
1105 };
1106 
1107 
1108 int SwFindParaAttr::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion,
1109                             sal_Bool bInReadOnly )
1110 {
1111     // String ersetzen ?? (nur wenn Text angegeben oder nicht attributiert
1112     //                      gesucht wird)
1113     sal_Bool bReplaceTxt = pSearchOpt && ( pSearchOpt->replaceString.getLength() ||
1114                                     !pSet->Count() );
1115     sal_Bool bReplaceAttr = pReplSet && pReplSet->Count();
1116     sal_Bool bMoveFirst = !bReplaceAttr;
1117     if( bInReadOnly && (bReplaceAttr || bReplaceTxt ))
1118         bInReadOnly = sal_False;
1119 
1120     // wir suchen nach Attributen, soll zusaetzlich Text gesucht werden ?
1121     {
1122         SwPaM aRegion( *pRegion->GetMark(), *pRegion->GetPoint() );
1123         SwPaM* pTextRegion = &aRegion;
1124         SwPaM aSrchPam( *pCrsr->GetPoint() );
1125 
1126         while( sal_True )
1127         {
1128             if( pSet->Count() )         // gibts ueberhaupt Attributierung?
1129             {
1130                 // zuerst die Attributierung
1131                 if( !aSrchPam.Find( *pSet, bValue, fnMove, &aRegion, bInReadOnly, bMoveFirst ) )
1132 //JP 17.11.95: was ist mit Attributen in leeren Absaetzen !!
1133 //                  || *pCrsr->GetMark() == *pCrsr->GetPoint() )    // kein Bereich ??
1134                     return FIND_NOT_FOUND;
1135                 bMoveFirst = sal_True;
1136 
1137                 if( !pSearchOpt )
1138                     break;      // ok, nur Attribute, also gefunden
1139 
1140                 pTextRegion = &aSrchPam;
1141             }
1142             else if( !pSearchOpt )
1143                 return FIND_NOT_FOUND;
1144 
1145             // dann darin den Text
1146             if( !pSTxt )
1147             {
1148                 SearchOptions aTmp( *pSearchOpt );
1149 
1150                 // search in selection
1151                 aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
1152                                     SearchFlags::REG_NOT_ENDOFLINE);
1153 
1154                 MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aTmp.Locale );
1155 
1156                 pSTxt = new utl::TextSearch( aTmp );
1157             }
1158 
1159             // todo/mba: searching for attributes in Outliner text?!
1160             sal_Bool bSearchInNotes = sal_False;
1161 
1162             // Bug 24665: suche im richtigen Bereich weiter (pTextRegion!)
1163             if( aSrchPam.Find( *pSearchOpt, bSearchInNotes, *pSTxt, fnMove, pTextRegion, bInReadOnly ) &&
1164                 *aSrchPam.GetMark() != *aSrchPam.GetPoint() )   // gefunden ?
1165                 break;                                      // also raus
1166             else if( !pSet->Count() )
1167                 return FIND_NOT_FOUND;      // nur Text und nicht gefunden
1168 
1169 /*          // --> FME 2007-4-12 #i74765 # Why should we move the position?
1170             Moving the position results in bugs when there are two adjacent
1171             portions which both have the requested attributes set. I suspect this
1172             should be only be an optimization. Therefore I boldly remove it now!
1173 
1174             // JP: und wieder neu aufsetzen, aber eine Position weiter
1175             //JP 04.11.97: Bug 44897 - aber den Mark wieder aufheben, damit
1176             //              weiterbewegt werden kann!
1177             {
1178                 sal_Bool bCheckRegion = sal_True;
1179                 SwPosition* pPos = aSrchPam.GetPoint();
1180                 if( !(*fnMove->fnNd)( &pPos->nNode.GetNode(),
1181                                         &pPos->nContent, CRSR_SKIP_CHARS ))
1182                 {
1183                     if( (*fnMove->fnNds)( &pPos->nNode, sal_False ))
1184                     {
1185                         SwCntntNode *pNd = pPos->nNode.GetNode().GetCntntNode();
1186                         xub_StrLen nCPos;
1187                         if( fnMove == fnMoveForward )
1188                             nCPos = 0;
1189                         else
1190                             nCPos = pNd->Len();
1191                         pPos->nContent.Assign( pNd, nCPos );
1192                     }
1193                     else
1194                         bCheckRegion = sal_False;
1195                 }
1196                 if( !bCheckRegion || *aRegion.GetPoint() <= *pPos )
1197                     return FIND_NOT_FOUND;      // nicht gefunden
1198             }*/
1199             *aRegion.GetMark() = *aSrchPam.GetPoint();
1200         }
1201 
1202         *pCrsr->GetPoint() = *aSrchPam.GetPoint();
1203         pCrsr->SetMark();
1204         *pCrsr->GetMark() = *aSrchPam.GetMark();
1205     }
1206 
1207     if( bReplaceTxt )
1208     {
1209         const bool bRegExp(
1210                 SearchAlgorithms_REGEXP == pSearchOpt->algorithmType);
1211         SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
1212         xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
1213 
1214         // damit die Region auch verschoben wird, in den Shell-Cursr-Ring
1215         // mit aufnehmen !!
1216         Ring *pPrevRing = 0;
1217         if( bRegExp )
1218         {
1219             pPrevRing = pRegion->GetPrev();
1220             ((Ring*)pRegion)->MoveRingTo( &rCursor );
1221         }
1222 
1223         ::std::auto_ptr<String> pRepl( (bRegExp) ?
1224                 ReplaceBackReferences( *pSearchOpt, pCrsr ) : 0 );
1225         rCursor.GetDoc()->ReplaceRange( *pCrsr,
1226             (pRepl.get()) ? *pRepl : String(pSearchOpt->replaceString),
1227             bRegExp );
1228         rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
1229 
1230         if( bRegExp )
1231         {
1232             // und die Region wieder herausnehmen:
1233             Ring *p, *pNext = (Ring*)pRegion;
1234             do {
1235                 p = pNext;
1236                 pNext = p->GetNext();
1237                 p->MoveTo( (Ring*)pRegion );
1238             } while( p != pPrevRing );
1239         }
1240         rSttCntIdx = nSttCnt;
1241     }
1242 
1243     if( bReplaceAttr )
1244     {
1245         // --- Ist die Selection noch da ??????
1246 
1247         // und noch die Attribute setzen
1248 #ifdef OLD
1249         pCrsr->GetDoc()->Insert( *pCrsr, *pReplSet, 0 );
1250 #else
1251         //JP 13.07.95: alle gesuchten Attribute werden, wenn nicht im
1252         //              ReplaceSet angegeben, auf Default zurueck gesetzt
1253 
1254         if( !pSet->Count() )
1255         {
1256             pCrsr->GetDoc()->InsertItemSet( *pCrsr, *pReplSet, 0 );
1257         }
1258         else
1259         {
1260             SfxItemPool* pPool = pReplSet->GetPool();
1261             SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
1262 
1263             SfxItemIter aIter( *pSet );
1264             const SfxPoolItem* pItem = aIter.GetCurItem();
1265             while( sal_True )
1266             {
1267                 // alle die nicht gesetzt sind mit Pool-Defaults aufuellen
1268                 if( !IsInvalidItem( pItem ) && SFX_ITEM_SET !=
1269                     pReplSet->GetItemState( pItem->Which(), sal_False ))
1270                     aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
1271 
1272                 if( aIter.IsAtEnd() )
1273                     break;
1274                 pItem = aIter.NextItem();
1275             }
1276             aSet.Put( *pReplSet );
1277             pCrsr->GetDoc()->InsertItemSet( *pCrsr, aSet, 0 );
1278         }
1279 #endif
1280         return FIND_NO_RING;
1281     }
1282 
1283     else
1284         return FIND_FOUND;
1285 }
1286 
1287 
1288 int SwFindParaAttr::IsReplaceMode() const
1289 {
1290     return ( pSearchOpt && pSearchOpt->replaceString.getLength() ) ||
1291            ( pReplSet && pReplSet->Count() );
1292 }
1293 
1294 // Suchen nach Attributen
1295 
1296 
1297 sal_uLong SwCursor::Find( const SfxItemSet& rSet, sal_Bool bNoCollections,
1298                     SwDocPositions nStart, SwDocPositions nEnde, sal_Bool& bCancel,
1299                     FindRanges eFndRngs,
1300                     const SearchOptions* pSearchOpt, const SfxItemSet* pReplSet )
1301 {
1302     // OLE-Benachrichtigung abschalten !!
1303     SwDoc* pDoc = GetDoc();
1304     Link aLnk( pDoc->GetOle2Link() );
1305     pDoc->SetOle2Link( Link() );
1306 
1307     sal_Bool bReplace = ( pSearchOpt && ( pSearchOpt->replaceString.getLength() ||
1308                                     !rSet.Count() ) ) ||
1309                     (pReplSet && pReplSet->Count());
1310     bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
1311     if (bStartUndo)
1312     {
1313         pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
1314     }
1315 
1316     SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
1317                                     pReplSet, *this );
1318 
1319     sal_uLong nRet = FindAll(aSwFindParaAttr, nStart, nEnde, eFndRngs, bCancel );
1320     pDoc->SetOle2Link( aLnk );
1321     if( nRet && bReplace )
1322         pDoc->SetModified();
1323 
1324     if (bStartUndo)
1325     {
1326         pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, NULL );
1327     }
1328 
1329     return nRet;
1330 }
1331 
1332 
1333 
1334