xref: /AOO41X/main/sw/source/core/crsr/findattr.cxx (revision 69a743679e823ad8f875be547552acb607b8ada5)
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 )
SV_IMPL_PTRARR_SORT(SwpFmts,SwFmt *)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 
GetFrwrdTxtHint(const SwpHints & rHtsArr,sal_uInt16 & rPos,xub_StrLen nCntntPos)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 
GetBkwrdTxtHint(const SwpHints & rHtsArr,sal_uInt16 & rPos,xub_StrLen nCntntPos)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 
lcl_SetAttrPam(SwPaM & rPam,xub_StrLen nStart,const xub_StrLen * pEnde,const sal_Bool bSaveMark)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 
lcl_Search(const SwTxtNode & rTxtNd,SwPaM & rPam,const SfxPoolItem & rCmpItem,SwMoveFn fnMove,sal_Bool bValue)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 
_SwSrchChrAttr_SwSrchChrAttr171     _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 ??
Count() const194     sal_uInt16 Count() const    { return aCmpSet.Count(); }
Found() const195     int Found() const       { return nFound == aCmpSet.Count(); }
196     int CheckStack();
197 
198     xub_StrLen Start() const;
199     xub_StrLen End() const;
200 
GetNdStt() const201     xub_StrLen GetNdStt() const { return nNdStt; }
GetNdEnd() const202     xub_StrLen GetNdEnd() const { return nNdEnd; }
203 
204     int SetAttrFwd( const SwTxtAttr& rAttr );
205     int SetAttrBwd( const SwTxtAttr& rAttr );
206 };
207 
208 
209 
SwAttrCheckArr(const SfxItemSet & rSet,int bFwd,int bNoCollections)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 
~SwAttrCheckArr()231 SwAttrCheckArr::~SwAttrCheckArr()
232 {
233     delete[] (char*)pFndArr;
234     delete[] (char*)pStackArr;
235 }
236 
SetNewSet(const SwTxtNode & rTxtNd,const SwPaM & rPam)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
lcl_IsAttributeIgnorable(xub_StrLen const nNdStart,xub_StrLen const nNdEnd,_SwSrchChrAttr const & rTmp)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 
SetAttrFwd(const SwTxtAttr & rAttr)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     return Found();
484 }
485 
486 
SetAttrBwd(const SwTxtAttr & rAttr)487 int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr& rAttr )
488 {
489     _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
490 
491     // ignore all attributes not in search range
492     if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
493     {
494         return Found();
495     }
496 
497     const SfxPoolItem* pItem;
498 // --------------------------------------------------------------
499 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
500 // --------------------------------------------------------------
501     sal_uInt16 nWhch = rAttr.Which();
502     SfxWhichIter* pIter = NULL;
503     const SfxPoolItem* pTmpItem = NULL;
504     const SfxItemSet* pSet = NULL;
505     if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
506     {
507         if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
508             return Found();
509 
510         pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
511         if ( pSet )
512         {
513             pIter = new SfxWhichIter( *pSet );
514             nWhch = pIter->FirstWhich();
515             while( nWhch &&
516                 SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
517                 nWhch = pIter->NextWhich();
518             if( !nWhch )
519                 pTmpItem = NULL;
520         }
521     }
522     else
523         pTmpItem = &rAttr.GetAttr();
524     while( pTmpItem )
525     {
526         SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
527         if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
528         {
529             sal_uInt16 n;
530             _SwSrchChrAttr* pCmp;
531 
532             // loesche erstmal alle, die bis zu der Start Position schon wieder
533             // ungueltig sind:
534 
535             _SwSrchChrAttr* pArrPtr;
536             if( nFound )
537                 for( pArrPtr = pFndArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
538                     if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd )
539                     {
540                         pArrPtr->nWhich = 0;        // geloescht
541                         nFound--;
542                     }
543 
544             // loesche erstmal alle, die bis zu der Start Position schon wieder
545             // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
546             // die Start Position ragen, vom Stack in den FndSet
547 
548             if( nStackCnt )
549                 for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
550                 {
551                     if( !pArrPtr->nWhich )
552                         continue;
553 
554                     if( pArrPtr->nStt >= aTmp.nEnd )
555                     {
556                         pArrPtr->nWhich = 0;        // geloescht
557                         if( !--nStackCnt )
558                             break;
559                     }
560                     else if( pArrPtr->nEnd >= aTmp.nEnd )
561                     {
562                         if( ( pCmp = &pFndArr[ n ])->nWhich )
563                         {
564                             if( pCmp->nStt > pArrPtr->nStt )        // erweitern
565                                 pCmp->nStt = pArrPtr->nStt;
566                         }
567                         else
568                         {
569                             *pCmp = *pArrPtr;
570                             nFound++;
571                     }
572                     pArrPtr->nWhich = 0;
573                     if( !--nStackCnt )
574                         break;
575                 }
576             }
577 
578             sal_Bool bContinue = sal_False;
579             if( SFX_ITEM_DONTCARE == eState  )
580             {
581                 // wird Attribut gueltig ?
582                 if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
583                     *pTmpItem ) )
584                 {
585                     // suche das Attribut und erweiter es gegebenenfalls
586                     if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
587                     {
588                         *pCmp = aTmp;               // nicht gefunden, eintragen
589                         nFound++;
590                     }
591                     else if( pCmp->nStt > aTmp.nStt )       // erweitern ?
592                         pCmp->nStt = aTmp.nStt;
593 
594                     bContinue = sal_True;
595                 }
596             }
597             // wird Attribut gueltig ?
598             else if( CmpAttr( *pItem, *pTmpItem ))
599             {
600                 pFndArr[ nWhch - nArrStart ] = aTmp;
601                 ++nFound;
602                 bContinue = sal_True;
603             }
604 
605             // tja, dann muss es auf den Stack
606             if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
607             {
608                 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
609                 if( pCmp->nStt < aTmp.nStt )
610                 {
611                     ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich,
612                             "Stack-Platz ist noch belegt" );
613 
614 // ---------
615 // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
616 //          pCmp->nEnd = aTmp.nStt;
617                     if( aTmp.nEnd <= pCmp->nEnd )
618                         pCmp->nEnd = aTmp.nStt;
619                     else
620                         pCmp->nStt = aTmp.nEnd;
621 // ---------
622 
623                     pStackArr[ nWhch - nArrStart ] = *pCmp;
624                     nStackCnt++;
625                 }
626                 pCmp->nWhich = 0;
627                 nFound--;
628             }
629         }
630         if( pIter )
631         {
632             nWhch = pIter->NextWhich();
633             while( nWhch &&
634                 SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
635                 nWhch = pIter->NextWhich();
636             if( !nWhch )
637                 break;
638         }
639         else
640             break;
641     }
642     return Found();
643 }
644 
645 
Start() const646 xub_StrLen SwAttrCheckArr::Start() const
647 {
648     xub_StrLen nStart = nNdStt;
649     _SwSrchChrAttr* pArrPtr = pFndArr;
650     for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
651         if( pArrPtr->nWhich && pArrPtr->nStt > nStart )
652             nStart = pArrPtr->nStt;
653 
654     return nStart;
655 }
656 
657 
End() const658 xub_StrLen SwAttrCheckArr::End() const
659 {
660     _SwSrchChrAttr* pArrPtr = pFndArr;
661     xub_StrLen nEnd = nNdEnd;
662     for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
663         if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd )
664             nEnd = pArrPtr->nEnd;
665 
666     return nEnd;
667 }
668 
669 
CheckStack()670 int SwAttrCheckArr::CheckStack()
671 {
672     if( !nStackCnt )
673         return sal_False;
674 
675     sal_uInt16 n;
676     xub_StrLen nSttPos = Start(), nEndPos = End();
677     _SwSrchChrAttr* pArrPtr;
678     for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
679     {
680         if( !pArrPtr->nWhich )
681             continue;
682 
683         if( bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos )
684         {
685             pArrPtr->nWhich = 0;        // geloescht
686             if( !--nStackCnt )
687                 return nFound == aCmpSet.Count();
688         }
689         else if( bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos )
690         {
691             // alle die "offen" sind, heisst ueber die Start Position ragen,
692             // im FndSet setzen
693             ASSERT( !pFndArr[ n ].nWhich, "Array-Platz ist noch belegt" );
694             pFndArr[ n ] = *pArrPtr;
695             pArrPtr->nWhich = 0;
696             nFound++;
697             if( !--nStackCnt )
698                 return nFound == aCmpSet.Count();
699         }
700     }
701     return nFound == aCmpSet.Count();
702 }
703 
704 
705 
lcl_SearchForward(const SwTxtNode & rTxtNd,SwAttrCheckArr & rCmpArr,SwPaM & rPam)706 int lcl_SearchForward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
707                             SwPaM& rPam )
708 {
709     xub_StrLen nEndPos, nSttPos;
710     rCmpArr.SetNewSet( rTxtNd, rPam );
711     if( !rTxtNd.HasHints() )
712     {
713         if( !rCmpArr.Found() )
714             return sal_False;
715         nEndPos = rCmpArr.GetNdEnd();
716         lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
717         return sal_True;
718     }
719 
720     // dann gehe mal durch das nach "Start" sortierte Array
721     const SwpHints& rHtArr = rTxtNd.GetSwpHints();
722     const SwTxtAttr* pAttr;
723     sal_uInt16 nPos = 0;
724 
725     // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
726     // das wieder beendet wird.
727     if( rCmpArr.Found() )
728     {
729         for( ; nPos < rHtArr.Count(); ++nPos )
730             if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
731             {
732                 if( rCmpArr.GetNdStt() < *pAttr->GetStart() )
733                 {
734                     // dann haben wir unser Ende:
735                     lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
736                                 pAttr->GetStart(), sal_True );
737                     return sal_True;
738                 }
739                 // ansonsten muessen wir weiter suchen
740                 break;
741             }
742 
743         if( nPos == rHtArr.Count() && rCmpArr.Found() )
744         {
745             // dann haben wir unseren Bereich
746             nEndPos = rCmpArr.GetNdEnd();
747             lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
748             return sal_True;
749         }
750     }
751 
752     for( ; nPos < rHtArr.Count(); ++nPos )
753         if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
754         {
755             // sollten noch mehr auf der gleichen Position anfangen ??
756             // auch die noch mit testen !!
757             nSttPos = *pAttr->GetStart();
758             while( ++nPos < rHtArr.Count() && nSttPos ==
759                     *( pAttr = rHtArr.GetStart( nPos ))->GetStart() &&
760                     rCmpArr.SetAttrFwd( *pAttr ) )
761                 ;
762             if( !rCmpArr.Found() )
763                 continue;
764 
765             // dann haben wir den Bereich zusammen
766             if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
767                 return sal_False;
768             lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
769             return sal_True;
770         }
771 
772     if( !rCmpArr.CheckStack() ||
773         (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
774         return sal_False;
775     lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
776     return sal_True;
777 }
778 
779 
lcl_SearchBackward(const SwTxtNode & rTxtNd,SwAttrCheckArr & rCmpArr,SwPaM & rPam)780 int lcl_SearchBackward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
781                             SwPaM& rPam )
782 {
783     xub_StrLen nEndPos, nSttPos;
784     rCmpArr.SetNewSet( rTxtNd, rPam );
785     if( !rTxtNd.HasHints() )
786     {
787         if( !rCmpArr.Found() )
788             return sal_False;
789         nEndPos = rCmpArr.GetNdEnd();
790         lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
791         return sal_True;
792     }
793 
794     // dann gehe mal durch das nach "Start" sortierte Array
795     const SwpHints& rHtArr = rTxtNd.GetSwpHints();
796     const SwTxtAttr* pAttr;
797     sal_uInt16 nPos = rHtArr.Count();
798 
799     // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
800     // das wieder beendet wird.
801     if( rCmpArr.Found() )
802     {
803         while( nPos )
804             if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
805             {
806                 nSttPos = *pAttr->GetAnyEnd();
807                 if( nSttPos < rCmpArr.GetNdEnd() )
808                 {
809                     // dann haben wir unser Ende:
810                     nEndPos = rCmpArr.GetNdEnd();
811                     lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
812                     return sal_True;
813                 }
814 
815                 // ansonsten muessen wir weiter suchen
816                 break;
817             }
818 
819         if( !nPos && rCmpArr.Found() )
820         {
821             // dann haben wir unseren Bereich
822             nEndPos = rCmpArr.GetNdEnd();
823             lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
824             return sal_True;
825         }
826     }
827 
828     while( nPos )
829         if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
830         {
831             // sollten noch mehr auf der gleichen Position anfangen ??
832             // auch die noch mit testen !!
833             if( nPos )
834             {
835                 nEndPos = *pAttr->GetAnyEnd();
836                 while( --nPos && nEndPos ==
837                         *( pAttr = rHtArr.GetEnd( nPos ))->GetAnyEnd() &&
838                         rCmpArr.SetAttrBwd( *pAttr ) )
839                     ;
840             }
841             if( !rCmpArr.Found() )
842                 continue;
843 
844 
845             // dann haben wir den Bereich zusammen
846             if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
847                 return sal_False;
848             lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
849             return sal_True;
850         }
851 
852     if( !rCmpArr.CheckStack() ||
853         (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
854         return sal_False;
855     lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
856     return sal_True;
857 }
858 
859 
lcl_Search(const SwCntntNode & rCNd,const SfxItemSet & rCmpSet,sal_Bool bNoColls)860 int lcl_Search( const SwCntntNode& rCNd, const SfxItemSet& rCmpSet, sal_Bool bNoColls )
861 {
862     // nur die harte Attributierung suchen ?
863     if( bNoColls && !rCNd.HasSwAttrSet() )
864         return sal_False;
865 
866     const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
867     SfxItemIter aIter( rCmpSet );
868     const SfxPoolItem* pItem = aIter.GetCurItem();
869     const SfxPoolItem* pNdItem;
870     sal_uInt16 nWhich;
871 
872     while( sal_True )
873     {
874         // nur testen, ob vorhanden ist ?
875         if( IsInvalidItem( pItem ))
876         {
877             nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
878             if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
879                 || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
880                 return sal_False;
881         }
882         else
883         {
884             nWhich = pItem->Which();
885 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
886 //              runter
887 //          if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
888 //              || *pNdItem != *pItem )
889             if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
890                 return sal_False;
891         }
892 
893         if( aIter.IsAtEnd() )
894             break;
895         pItem = aIter.NextItem();
896     }
897     return sal_True;            // wurde gefunden
898 }
899 
900 
Find(const SfxPoolItem & rAttr,sal_Bool bValue,SwMoveFn fnMove,const SwPaM * pRegion,sal_Bool bInReadOnly)901 sal_Bool SwPaM::Find( const SfxPoolItem& rAttr, sal_Bool bValue, SwMoveFn fnMove,
902                     const SwPaM *pRegion, sal_Bool bInReadOnly )
903 {
904     // stelle fest welches Attribut gesucht wird:
905     const sal_uInt16 nWhich = rAttr.Which();
906     int bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
907 
908     SwPaM* pPam = MakeRegion( fnMove, pRegion );
909 
910     sal_Bool bFound = sal_False;
911     sal_Bool bFirst = sal_True;
912     sal_Bool bSrchForward = fnMove == fnMoveForward;
913     SwCntntNode * pNode;
914     const SfxPoolItem* pItem;
915     SwpFmts aFmtArr;
916 
917     // Wenn am Anfang/Ende, aus dem Node moven
918     if( bSrchForward
919         ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
920         : !pPam->GetPoint()->nContent.GetIndex() )
921     {
922         if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
923         {
924             delete pPam;
925             return sal_False;
926         }
927         SwCntntNode *pNd = pPam->GetCntntNode();
928         xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
929         pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
930     }
931 
932     while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
933     {
934         if( bCharAttr )
935         {
936             if( !pNode->IsTxtNode() )       // CharAttr sind nur in TextNodes
937                 continue;
938 
939             if( ((SwTxtNode*)pNode)->HasHints() &&
940                 lcl_Search( *(SwTxtNode*)pNode, *pPam, rAttr, fnMove,  bValue ))
941             {
942                 // setze auf die Werte vom Attribut
943                 SetMark();
944                 *GetPoint() = *pPam->GetPoint();
945                 *GetMark() = *pPam->GetMark();
946                 bFound = sal_True;
947                 break;
948             }
949             else if (isTXTATR(nWhich))
950                 continue;               // --> also weiter
951         }
952 
953         // keine harte Attributierung, dann pruefe, ob die Vorlage schon
954         // mal nach dem Attribut befragt wurde
955         if( !pNode->HasSwAttrSet() )
956         {
957             const SwFmt* pTmpFmt = pNode->GetFmtColl();
958             if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
959                 continue;   // die Collection wurde schon mal befragt
960             aFmtArr.Insert( pTmpFmt );
961         }
962 
963         if( SFX_ITEM_SET == pNode->GetSwAttrSet().GetItemState( nWhich,
964             sal_True, &pItem ) && ( !bValue || *pItem == rAttr ) )
965         {
966             // FORWARD:  Point an das Ende, GetMark zum Anfanf vom Node
967             // BACKWARD: Point zum Anfang,  GetMark an das Ende vom Node
968             // und immer nach der Logik: inkl. Start, exkl. End !!!
969             *GetPoint() = *pPam->GetPoint();
970             SetMark();
971             pNode->MakeEndIndex( &GetPoint()->nContent );
972             bFound = sal_True;
973             break;
974         }
975     }
976 
977     // beim rueckwaerts Suchen noch Point und Mark vertauschen
978     if( bFound && !bSrchForward )
979         Exchange();
980 
981     delete pPam;
982     return bFound;
983 }
984 
985 
986 typedef int (*FnSearchAttr)( const SwTxtNode&, SwAttrCheckArr&, SwPaM& );
987 
Find(const SfxItemSet & rSet,sal_Bool bNoColls,SwMoveFn fnMove,const SwPaM * pRegion,sal_Bool bInReadOnly,sal_Bool bMoveFirst)988 sal_Bool SwPaM::Find( const SfxItemSet& rSet, sal_Bool bNoColls, SwMoveFn fnMove,
989                     const SwPaM *pRegion, sal_Bool bInReadOnly, sal_Bool bMoveFirst )
990 {
991     SwPaM* pPam = MakeRegion( fnMove, pRegion );
992 
993     sal_Bool bFound = sal_False;
994     sal_Bool bFirst = sal_True;
995     sal_Bool bSrchForward = fnMove == fnMoveForward;
996     SwCntntNode * pNode;
997     SwpFmts aFmtArr;
998 
999     // teste doch mal welche Text/Char-Attribute gesucht werden
1000     SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
1001     SfxItemSet aOtherSet( GetDoc()->GetAttrPool(),
1002                             RES_PARATR_BEGIN, RES_GRFATR_END-1 );
1003     aOtherSet.Put( rSet, sal_False );   // alle Invalid-Items erhalten!
1004 
1005     FnSearchAttr fnSearch = bSrchForward
1006                                 ? (&::lcl_SearchForward)
1007                                 : (&::lcl_SearchBackward);
1008 
1009     // Wenn am Anfang/Ende, aus dem Node moven
1010     // Wenn am Anfang/Ende, aus dem Node moven
1011     if( bMoveFirst &&
1012         ( bSrchForward
1013         ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
1014         : !pPam->GetPoint()->nContent.GetIndex() ) )
1015     {
1016         if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
1017         {
1018             delete pPam;
1019             return sal_False;
1020         }
1021         SwCntntNode *pNd = pPam->GetCntntNode();
1022         xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
1023         pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
1024     }
1025 
1026 
1027     while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
1028     {
1029         if( aCmpArr.Count() )
1030         {
1031             if( !pNode->IsTxtNode() )       // CharAttr sind nur in TextNodes
1032                 continue;
1033 
1034             if( (!aOtherSet.Count() ||
1035                 lcl_Search( *pNode, aOtherSet, bNoColls )) &&
1036                 (*fnSearch)( *(SwTxtNode*)pNode, aCmpArr, *pPam ))
1037             {
1038                 // setze auf die Werte vom Attribut
1039                 SetMark();
1040                 *GetPoint() = *pPam->GetPoint();
1041                 *GetMark() = *pPam->GetMark();
1042                 bFound = sal_True;
1043                 break;
1044             }
1045             continue;       // TextAttribute
1046         }
1047 
1048         if( !aOtherSet.Count() )
1049             continue;
1050 
1051         // keine harte Attributierung, dann pruefe, ob die Vorlage schon
1052         // mal nach dem Attribut befragt wurde
1053         if( !pNode->HasSwAttrSet() )
1054         {
1055             const SwFmt* pTmpFmt = pNode->GetFmtColl();
1056             if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
1057                 continue;   // die Collection wurde schon mal befragt
1058             aFmtArr.Insert( pTmpFmt );
1059         }
1060 
1061         if( lcl_Search( *pNode, aOtherSet, bNoColls ))
1062         {
1063             // FORWARD:  Point an das Ende, GetMark zum Anfanf vom Node
1064             // BACKWARD: Point zum Anfang,  GetMark an das Ende vom Node
1065             // und immer nach der Logik: inkl. Start, exkl. End !!!
1066             *GetPoint() = *pPam->GetPoint();
1067             SetMark();
1068             pNode->MakeEndIndex( &GetPoint()->nContent );
1069             bFound = sal_True;
1070             break;
1071         }
1072     }
1073 
1074     // beim rueckwaerts Suchen noch Point und Mark vertauschen
1075     if( bFound && !bSrchForward )
1076         Exchange();
1077 
1078     delete pPam;
1079     return bFound;
1080 }
1081 
1082 //------------------ Methoden vom SwCursor ---------------------------
1083 
1084 // Parameter fuer das Suchen vom Attributen
1085 struct SwFindParaAttr : public SwFindParas
1086 {
1087     sal_Bool bValue;
1088     const SfxItemSet *pSet, *pReplSet;
1089     const SearchOptions *pSearchOpt;
1090     SwCursor& rCursor;
1091     utl::TextSearch* pSTxt;
1092 
SwFindParaAttrSwFindParaAttr1093     SwFindParaAttr( const SfxItemSet& rSet, sal_Bool bNoCollection,
1094                     const SearchOptions* pOpt, const SfxItemSet* pRSet,
1095                     SwCursor& rCrsr )
1096         : bValue( bNoCollection ), pSet( &rSet ), pReplSet( pRSet ),
1097           pSearchOpt( pOpt ), rCursor( rCrsr ),pSTxt( 0 ) {}
1098 
~SwFindParaAttrSwFindParaAttr1099     virtual ~SwFindParaAttr()   { delete pSTxt; }
1100 
1101     virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
1102     virtual int IsReplaceMode() const;
1103 };
1104 
1105 
Find(SwPaM * pCrsr,SwMoveFn fnMove,const SwPaM * pRegion,sal_Bool bInReadOnly)1106 int SwFindParaAttr::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion,
1107                             sal_Bool bInReadOnly )
1108 {
1109     // String ersetzen ?? (nur wenn Text angegeben oder nicht attributiert
1110     //                      gesucht wird)
1111     sal_Bool bReplaceTxt = pSearchOpt && ( pSearchOpt->replaceString.getLength() ||
1112                                     !pSet->Count() );
1113     sal_Bool bReplaceAttr = pReplSet && pReplSet->Count();
1114     sal_Bool bMoveFirst = !bReplaceAttr;
1115     if( bInReadOnly && (bReplaceAttr || bReplaceTxt ))
1116         bInReadOnly = sal_False;
1117 
1118     // wir suchen nach Attributen, soll zusaetzlich Text gesucht werden ?
1119     {
1120         SwPaM aRegion( *pRegion->GetMark(), *pRegion->GetPoint() );
1121         SwPaM* pTextRegion = &aRegion;
1122         SwPaM aSrchPam( *pCrsr->GetPoint() );
1123 
1124         while( sal_True )
1125         {
1126             if( pSet->Count() )         // gibts ueberhaupt Attributierung?
1127             {
1128                 // zuerst die Attributierung
1129                 if( !aSrchPam.Find( *pSet, bValue, fnMove, &aRegion, bInReadOnly, bMoveFirst ) )
1130 //JP 17.11.95: was ist mit Attributen in leeren Absaetzen !!
1131 //                  || *pCrsr->GetMark() == *pCrsr->GetPoint() )    // kein Bereich ??
1132                     return FIND_NOT_FOUND;
1133                 bMoveFirst = sal_True;
1134 
1135                 if( !pSearchOpt )
1136                     break;      // ok, nur Attribute, also gefunden
1137 
1138                 pTextRegion = &aSrchPam;
1139             }
1140             else if( !pSearchOpt )
1141                 return FIND_NOT_FOUND;
1142 
1143             // dann darin den Text
1144             if( !pSTxt )
1145             {
1146                 SearchOptions aTmp( *pSearchOpt );
1147 
1148                 // search in selection
1149                 aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
1150                                     SearchFlags::REG_NOT_ENDOFLINE);
1151 
1152                 MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aTmp.Locale );
1153 
1154                 pSTxt = new utl::TextSearch( aTmp );
1155             }
1156 
1157             // todo/mba: searching for attributes in Outliner text?!
1158             sal_Bool bSearchInNotes = sal_False;
1159 
1160             // Bug 24665: suche im richtigen Bereich weiter (pTextRegion!)
1161             if( aSrchPam.Find( *pSearchOpt, bSearchInNotes, *pSTxt, fnMove, pTextRegion, bInReadOnly ) &&
1162                 *aSrchPam.GetMark() != *aSrchPam.GetPoint() )   // gefunden ?
1163                 break;                                      // also raus
1164             else if( !pSet->Count() )
1165                 return FIND_NOT_FOUND;      // nur Text und nicht gefunden
1166 
1167 /*          // --> FME 2007-4-12 #i74765 # Why should we move the position?
1168             Moving the position results in bugs when there are two adjacent
1169             portions which both have the requested attributes set. I suspect this
1170             should be only be an optimization. Therefore I boldly remove it now!
1171 
1172             // JP: und wieder neu aufsetzen, aber eine Position weiter
1173             //JP 04.11.97: Bug 44897 - aber den Mark wieder aufheben, damit
1174             //              weiterbewegt werden kann!
1175             {
1176                 sal_Bool bCheckRegion = sal_True;
1177                 SwPosition* pPos = aSrchPam.GetPoint();
1178                 if( !(*fnMove->fnNd)( &pPos->nNode.GetNode(),
1179                                         &pPos->nContent, CRSR_SKIP_CHARS ))
1180                 {
1181                     if( (*fnMove->fnNds)( &pPos->nNode, sal_False ))
1182                     {
1183                         SwCntntNode *pNd = pPos->nNode.GetNode().GetCntntNode();
1184                         xub_StrLen nCPos;
1185                         if( fnMove == fnMoveForward )
1186                             nCPos = 0;
1187                         else
1188                             nCPos = pNd->Len();
1189                         pPos->nContent.Assign( pNd, nCPos );
1190                     }
1191                     else
1192                         bCheckRegion = sal_False;
1193                 }
1194                 if( !bCheckRegion || *aRegion.GetPoint() <= *pPos )
1195                     return FIND_NOT_FOUND;      // nicht gefunden
1196             }*/
1197             *aRegion.GetMark() = *aSrchPam.GetPoint();
1198         }
1199 
1200         *pCrsr->GetPoint() = *aSrchPam.GetPoint();
1201         pCrsr->SetMark();
1202         *pCrsr->GetMark() = *aSrchPam.GetMark();
1203     }
1204 
1205     if( bReplaceTxt )
1206     {
1207         const bool bRegExp(
1208                 SearchAlgorithms_REGEXP == pSearchOpt->algorithmType);
1209         SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
1210         xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
1211 
1212         // damit die Region auch verschoben wird, in den Shell-Cursr-Ring
1213         // mit aufnehmen !!
1214         Ring *pPrevRing = 0;
1215         if( bRegExp )
1216         {
1217             pPrevRing = pRegion->GetPrev();
1218             ((Ring*)pRegion)->MoveRingTo( &rCursor );
1219         }
1220 
1221         ::std::auto_ptr<String> pRepl( (bRegExp) ?
1222                 ReplaceBackReferences( *pSearchOpt, pCrsr ) : 0 );
1223         rCursor.GetDoc()->ReplaceRange( *pCrsr,
1224             (pRepl.get()) ? *pRepl : String(pSearchOpt->replaceString),
1225             bRegExp );
1226         rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
1227 
1228         if( bRegExp )
1229         {
1230             // und die Region wieder herausnehmen:
1231             Ring *p, *pNext = (Ring*)pRegion;
1232             do {
1233                 p = pNext;
1234                 pNext = p->GetNext();
1235                 p->MoveTo( (Ring*)pRegion );
1236             } while( p != pPrevRing );
1237         }
1238         rSttCntIdx = nSttCnt;
1239     }
1240 
1241     if( bReplaceAttr )
1242     {
1243         // --- Ist die Selection noch da ??????
1244 
1245         // und noch die Attribute setzen
1246 #ifdef OLD
1247         pCrsr->GetDoc()->Insert( *pCrsr, *pReplSet, 0 );
1248 #else
1249         //JP 13.07.95: alle gesuchten Attribute werden, wenn nicht im
1250         //              ReplaceSet angegeben, auf Default zurueck gesetzt
1251 
1252         if( !pSet->Count() )
1253         {
1254             pCrsr->GetDoc()->InsertItemSet( *pCrsr, *pReplSet, 0 );
1255         }
1256         else
1257         {
1258             SfxItemPool* pPool = pReplSet->GetPool();
1259             SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
1260 
1261             SfxItemIter aIter( *pSet );
1262             const SfxPoolItem* pItem = aIter.GetCurItem();
1263             while( sal_True )
1264             {
1265                 // alle die nicht gesetzt sind mit Pool-Defaults aufuellen
1266                 if( !IsInvalidItem( pItem ) && SFX_ITEM_SET !=
1267                     pReplSet->GetItemState( pItem->Which(), sal_False ))
1268                     aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
1269 
1270                 if( aIter.IsAtEnd() )
1271                     break;
1272                 pItem = aIter.NextItem();
1273             }
1274             aSet.Put( *pReplSet );
1275             pCrsr->GetDoc()->InsertItemSet( *pCrsr, aSet, 0 );
1276         }
1277 #endif
1278         return FIND_NO_RING;
1279     }
1280 
1281     else
1282         return FIND_FOUND;
1283 }
1284 
1285 
IsReplaceMode() const1286 int SwFindParaAttr::IsReplaceMode() const
1287 {
1288     return ( pSearchOpt && pSearchOpt->replaceString.getLength() ) ||
1289            ( pReplSet && pReplSet->Count() );
1290 }
1291 
1292 // Suchen nach Attributen
1293 
1294 
Find(const SfxItemSet & rSet,sal_Bool bNoCollections,SwDocPositions nStart,SwDocPositions nEnde,sal_Bool & bCancel,FindRanges eFndRngs,const SearchOptions * pSearchOpt,const SfxItemSet * pReplSet)1295 sal_uLong SwCursor::Find( const SfxItemSet& rSet, sal_Bool bNoCollections,
1296                     SwDocPositions nStart, SwDocPositions nEnde, sal_Bool& bCancel,
1297                     FindRanges eFndRngs,
1298                     const SearchOptions* pSearchOpt, const SfxItemSet* pReplSet )
1299 {
1300     // OLE-Benachrichtigung abschalten !!
1301     SwDoc* pDoc = GetDoc();
1302     Link aLnk( pDoc->GetOle2Link() );
1303     pDoc->SetOle2Link( Link() );
1304 
1305     sal_Bool bReplace = ( pSearchOpt && ( pSearchOpt->replaceString.getLength() ||
1306                                     !rSet.Count() ) ) ||
1307                     (pReplSet && pReplSet->Count());
1308     bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
1309     if (bStartUndo)
1310     {
1311         pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
1312     }
1313 
1314     SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
1315                                     pReplSet, *this );
1316 
1317     sal_uLong nRet = FindAll(aSwFindParaAttr, nStart, nEnde, eFndRngs, bCancel );
1318     pDoc->SetOle2Link( aLnk );
1319     if( nRet && bReplace )
1320         pDoc->SetModified();
1321 
1322     if (bStartUndo)
1323     {
1324         pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, NULL );
1325     }
1326 
1327     return nRet;
1328 }
1329 
1330 
1331 
1332