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