Update ooo320-m1
[ooovba.git] / sw / source / core / crsr / findattr.cxx
blob61fefca66909627096f41e6e68a822d7f1fb4c11
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: findattr.cxx,v $
10 * $Revision: 1.20 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <com/sun/star/lang/Locale.hpp>
36 #include <com/sun/star/util/SearchOptions.hpp>
37 #include <com/sun/star/util/SearchFlags.hpp>
38 #include <i18npool/mslangid.hxx>
39 #include <hintids.hxx>
40 #include <vcl/svapp.hxx>
41 #include <svtools/itemiter.hxx>
42 #include <svtools/whiter.hxx>
43 #include <svx/brkitem.hxx>
44 #include <svx/colritem.hxx>
45 #include <svx/fontitem.hxx>
46 #include <fmtpdsc.hxx>
47 #include <txatbase.hxx>
48 #include <fchrfmt.hxx>
49 #include <charfmt.hxx>
50 #include <doc.hxx>
51 #include <swcrsr.hxx>
52 #include <editsh.hxx>
53 #include <ndtxt.hxx>
54 #include <pamtyp.hxx>
55 #include <swundo.hxx>
56 #include <crsskip.hxx>
57 #include <undobj.hxx>
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::lang;
61 using namespace ::com::sun::star::util;
63 SV_DECL_PTRARR_SORT( SwpFmts, SwFmt*, 0, 4 )
64 SV_IMPL_PTRARR_SORT( SwpFmts, SwFmt* )
66 // Sonderbehandlung fuer SvxFontItem, nur den Namen vergleichen:
67 int CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 )
69 switch( rItem1.Which() )
71 case RES_CHRATR_FONT:
72 return ((SvxFontItem&)rItem1).GetFamilyName() ==
73 ((SvxFontItem&)rItem2).GetFamilyName();
75 case RES_CHRATR_COLOR:
76 return ((SvxColorItem&)rItem1).GetValue().IsRGBEqual(
77 ((SvxColorItem&)rItem2).GetValue() );
78 case RES_PAGEDESC:
79 return ((SwFmtPageDesc&)rItem1).GetNumOffset() ==
80 ((SwFmtPageDesc&)rItem2).GetNumOffset() &&
81 ((SwFmtPageDesc&)rItem1).GetPageDesc() ==
82 ((SwFmtPageDesc&)rItem2).GetPageDesc();
84 return rItem1 == rItem2;
88 const SwTxtAttr* GetFrwrdTxtHint( const SwpHints& rHtsArr, USHORT& rPos,
89 xub_StrLen nCntntPos )
91 while( rPos < rHtsArr.Count() )
93 const SwTxtAttr *pTxtHt = rHtsArr.GetStart( rPos++ );
94 // der Start vom Attribut muss innerhalb des Bereiches liegen !!
95 if( *pTxtHt->GetStart() >= nCntntPos )
96 return pTxtHt; // gueltiges TextAttribut
98 return 0; // kein gueltiges TextAttribut
102 const SwTxtAttr* GetBkwrdTxtHint( const SwpHints& rHtsArr, USHORT& rPos,
103 xub_StrLen nCntntPos )
105 while( rPos > 0 )
107 //Hack mit cast fuer das Update
108 const SwTxtAttr *pTxtHt = rHtsArr.GetStart( --rPos );
109 // der Start vom Attribut muss innerhalb des Bereiches liegen !!
110 if( *pTxtHt->GetStart() < nCntntPos )
111 return pTxtHt; // gueltiges TextAttribut
113 return 0; // kein gueltiges TextAttribut
117 void lcl_SetAttrPam( SwPaM & rPam, xub_StrLen nStart, const xub_StrLen* pEnde,
118 const BOOL bSaveMark )
120 xub_StrLen nCntntPos;
121 if( bSaveMark )
122 nCntntPos = rPam.GetMark()->nContent.GetIndex();
123 else
124 nCntntPos = rPam.GetPoint()->nContent.GetIndex();
125 BOOL bTstEnde = rPam.GetPoint()->nNode == rPam.GetMark()->nNode;
127 SwCntntNode* pCNd = rPam.GetCntntNode();
128 rPam.GetPoint()->nContent.Assign( pCNd, nStart );
129 rPam.SetMark(); // Point == GetMark
131 // Point zeigt auf das Ende vom SuchBereich oder Ende vom Attribut
132 if( pEnde )
134 if( bTstEnde && *pEnde > nCntntPos )
135 rPam.GetPoint()->nContent = nCntntPos;
136 else
137 rPam.GetPoint()->nContent = *pEnde;
141 //------------------ Suche nach einem Text Attribut -----------------------
143 // diese Funktion sucht in einem TextNode nach dem vorgegebenen Attribut.
144 // Wird es gefunden, dann hat der SwPaM den Bereich der das Attribut
145 // umspannt, unter Beachtung des Suchbereiches
148 BOOL lcl_Search( const SwTxtNode& rTxtNd, SwPaM& rPam,
149 const SfxPoolItem& rCmpItem,
150 SwMoveFn fnMove, BOOL bValue )
152 if ( !rTxtNd.HasHints() )
153 return FALSE;
154 const SwTxtAttr *pTxtHt = 0;
155 BOOL bForward = fnMove == fnMoveForward;
156 USHORT nPos = bForward ? 0 : rTxtNd.GetSwpHints().Count();
157 xub_StrLen nCntntPos = rPam.GetPoint()->nContent.GetIndex();
159 while( 0 != ( pTxtHt=(*fnMove->fnGetHint)(rTxtNd.GetSwpHints(),nPos,nCntntPos)))
160 if( pTxtHt->Which() == rCmpItem.Which() &&
161 ( !bValue || CmpAttr( pTxtHt->GetAttr(), rCmpItem )))
163 lcl_SetAttrPam( rPam, *pTxtHt->GetStart(), pTxtHt->GetEnd(), bForward );
164 return TRUE;
166 return FALSE;
170 //------------------ Suche nach mehren Text Attributen -------------------
172 struct _SwSrchChrAttr
174 USHORT nWhich;
175 xub_StrLen nStt, nEnd;
177 _SwSrchChrAttr( const SfxPoolItem& rItem,
178 xub_StrLen nStart, xub_StrLen nAnyEnd )
179 : nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd )
183 class SwAttrCheckArr
185 _SwSrchChrAttr *pFndArr, *pStackArr;
186 xub_StrLen nNdStt, nNdEnd;
187 USHORT nArrStart, nArrLen;
188 USHORT nFound, nStackCnt;
189 SfxItemSet aCmpSet;
190 BOOL bNoColls;
191 BOOL bForward;
193 public:
194 SwAttrCheckArr( const SfxItemSet& rSet, int bForward, int bNoCollections );
195 ~SwAttrCheckArr();
197 void SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam );
199 // wieviele Attribute ueberhaupt ??
200 USHORT Count() const { return aCmpSet.Count(); }
201 int Found() const { return nFound == aCmpSet.Count(); }
202 int CheckStack();
204 xub_StrLen Start() const;
205 xub_StrLen End() const;
207 xub_StrLen GetNdStt() const { return nNdStt; }
208 xub_StrLen GetNdEnd() const { return nNdEnd; }
210 int SetAttrFwd( const SwTxtAttr& rAttr );
211 int SetAttrBwd( const SwTxtAttr& rAttr );
216 SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet& rSet, int bFwd,
217 int bNoCollections )
218 : aCmpSet( *rSet.GetPool(), RES_CHRATR_BEGIN, RES_TXTATR_END-1 )
220 aCmpSet.Put( rSet, FALSE );
221 bNoColls = 0 != bNoCollections;
223 bForward = 0 != bFwd;
225 // Bestimmen den Bereich des Fnd/Stack-Arrays (Min/Max)
226 SfxItemIter aIter( aCmpSet );
227 nArrStart = aCmpSet.GetWhichByPos( aIter.GetFirstPos() );
228 nArrLen = aCmpSet.GetWhichByPos( aIter.GetLastPos() ) - nArrStart+1;
230 char* pFndChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
231 char* pStackChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
233 pFndArr = (_SwSrchChrAttr*)pFndChar;
234 pStackArr = (_SwSrchChrAttr*)pStackChar;
237 SwAttrCheckArr::~SwAttrCheckArr()
239 delete[] (char*)pFndArr;
240 delete[] (char*)pStackArr;
243 void SwAttrCheckArr::SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam )
245 memset( pFndArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
246 memset( pStackArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
247 nFound = 0;
248 nStackCnt = 0;
250 if( bForward )
252 nNdStt = rPam.GetPoint()->nContent.GetIndex();
253 nNdEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
254 ? rPam.GetMark()->nContent.GetIndex()
255 : rTxtNd.GetTxt().Len();
257 else
259 nNdEnd = rPam.GetPoint()->nContent.GetIndex();
260 nNdStt = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
261 ? rPam.GetMark()->nContent.GetIndex()
262 : 0;
265 if( bNoColls && !rTxtNd.HasSwAttrSet() )
266 return ;
268 const SfxItemSet& rSet = rTxtNd.GetSwAttrSet();
269 // if( !rSet.Count() )
270 // return;
272 SfxItemIter aIter( aCmpSet );
273 const SfxPoolItem* pItem = aIter.GetCurItem();
274 const SfxPoolItem* pFndItem;
275 USHORT nWhich;
277 while( TRUE )
279 // nur testen, ob vorhanden ist ?
280 if( IsInvalidItem( pItem ) )
282 nWhich = aCmpSet.GetWhichByPos( aIter.GetCurPos() );
283 if( RES_TXTATR_END <= nWhich )
284 break; // Ende der TextAttribute
286 if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
287 && !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) ))
289 pFndArr[ nWhich - nArrStart ] =
290 _SwSrchChrAttr( *pFndItem, nNdStt, nNdEnd );
291 nFound++;
294 else
296 if( RES_TXTATR_END <= (nWhich = pItem->Which() ))
297 break; // Ende der TextAttribute
299 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
300 // runter
301 // if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
302 // && *pFndItem == *pItem )
303 if( CmpAttr( rSet.Get( nWhich, !bNoColls ), *pItem ) )
305 pFndArr[ nWhich - nArrStart ] =
306 _SwSrchChrAttr( *pItem, nNdStt, nNdEnd );
307 nFound++;
311 if( aIter.IsAtEnd() )
312 break;
313 pItem = aIter.NextItem();
316 int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr& rAttr )
318 _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
319 // alle die nicht im Bereich sind -> ignorieren
320 if( aTmp.nEnd <= nNdStt || aTmp.nStt >= nNdEnd )
321 return Found();
323 const SfxPoolItem* pItem;
325 // --------------------------------------------------------------
326 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
327 // --------------------------------------------------------------
328 USHORT nWhch = rAttr.Which();
329 SfxWhichIter* pIter = NULL;
330 const SfxPoolItem* pTmpItem = NULL;
331 const SfxItemSet* pSet = NULL;
332 if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
334 if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
335 return Found();
336 pTmpItem = NULL;
337 pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
338 if ( pSet )
340 pIter = new SfxWhichIter( *pSet );
341 nWhch = pIter->FirstWhich();
342 while( nWhch &&
343 SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) )
344 nWhch = pIter->NextWhich();
345 if( !nWhch )
346 pTmpItem = NULL;
349 else
350 pTmpItem = &rAttr.GetAttr();
351 while( pTmpItem )
353 SfxItemState eState = aCmpSet.GetItemState( nWhch, FALSE, &pItem );
354 if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
356 USHORT n;
357 _SwSrchChrAttr* pCmp;
359 // loesche erstmal alle, die bis zu der Start Position schon wieder
360 // ungueltig sind:
362 _SwSrchChrAttr* pArrPtr;
363 if( nFound )
364 for( pArrPtr = pFndArr, n = 0; n < nArrLen;
365 ++n, ++pArrPtr )
366 if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt )
368 pArrPtr->nWhich = 0; // geloescht
369 nFound--;
372 // loesche erstmal alle, die bis zu der Start Position schon wieder
373 // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
374 // die Start Position ragen, vom Stack in den FndSet
376 if( nStackCnt )
377 for( pArrPtr = pStackArr, n=0; n < nArrLen; ++n, ++pArrPtr )
379 if( !pArrPtr->nWhich )
380 continue;
382 if( pArrPtr->nEnd <= aTmp.nStt )
384 pArrPtr->nWhich = 0; // geloescht
385 if( !--nStackCnt )
386 break;
388 else if( pArrPtr->nStt <= aTmp.nStt )
390 if( ( pCmp = &pFndArr[ n ])->nWhich )
392 if( pCmp->nEnd < pArrPtr->nEnd ) // erweitern
393 pCmp->nEnd = pArrPtr->nEnd;
395 else
397 *pCmp = *pArrPtr;
398 nFound++;
400 pArrPtr->nWhich = 0;
401 if( !--nStackCnt )
402 break;
406 BOOL bContinue = FALSE;
408 if( SFX_ITEM_DONTCARE == eState )
410 // wird Attribut gueltig ?
411 if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
412 *pTmpItem ))
414 // suche das Attribut und erweiter es gegebenenfalls
415 if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
417 *pCmp = aTmp; // nicht gefunden, eintragen
418 nFound++;
420 else if( pCmp->nEnd < aTmp.nEnd ) // erweitern ?
421 pCmp->nEnd = aTmp.nEnd;
423 bContinue = TRUE;
426 // wird Attribut gueltig ?
427 else if( CmpAttr( *pItem, *pTmpItem ) )
429 pFndArr[ nWhch - nArrStart ] = aTmp;
430 ++nFound;
431 bContinue = TRUE;
434 // tja, dann muss es auf den Stack
435 if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
437 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
438 if( pCmp->nEnd > aTmp.nEnd )
440 ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich,
441 "Stack-Platz ist noch belegt" );
443 // ---------
444 // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
445 // pCmp->nStt = aTmp.nEnd;
446 if( aTmp.nStt <= pCmp->nStt )
447 pCmp->nStt = aTmp.nEnd;
448 else
449 pCmp->nEnd = aTmp.nStt;
450 // ---------
452 pStackArr[ nWhch - nArrStart ] = *pCmp;
453 nStackCnt++;
455 pCmp->nWhich = 0;
456 nFound--;
459 if( pIter )
461 nWhch = pIter->NextWhich();
462 while( nWhch &&
463 SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) )
464 nWhch = pIter->NextWhich();
465 if( !nWhch )
466 break;
468 else
469 break;
471 return Found();
475 int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr& rAttr )
477 _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
478 // alle die nicht im Bereich sind -> ignorieren
479 if( aTmp.nEnd < nNdStt || aTmp.nStt >= nNdEnd )
480 return Found();
482 const SfxPoolItem* pItem;
483 // --------------------------------------------------------------
484 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
485 // --------------------------------------------------------------
486 USHORT nWhch = rAttr.Which();
487 SfxWhichIter* pIter = NULL;
488 const SfxPoolItem* pTmpItem = NULL;
489 const SfxItemSet* pSet = NULL;
490 if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
492 if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
493 return Found();
495 pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
496 if ( pSet )
498 pIter = new SfxWhichIter( *pSet );
499 nWhch = pIter->FirstWhich();
500 while( nWhch &&
501 SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) )
502 nWhch = pIter->NextWhich();
503 if( !nWhch )
504 pTmpItem = NULL;
507 else
508 pTmpItem = &rAttr.GetAttr();
509 while( pTmpItem )
511 SfxItemState eState = aCmpSet.GetItemState( nWhch, FALSE, &pItem );
512 if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
514 USHORT n;
515 _SwSrchChrAttr* pCmp;
517 // loesche erstmal alle, die bis zu der Start Position schon wieder
518 // ungueltig sind:
520 _SwSrchChrAttr* pArrPtr;
521 if( nFound )
522 for( pArrPtr = pFndArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
523 if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd )
525 pArrPtr->nWhich = 0; // geloescht
526 nFound--;
529 // loesche erstmal alle, die bis zu der Start Position schon wieder
530 // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
531 // die Start Position ragen, vom Stack in den FndSet
533 if( nStackCnt )
534 for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
536 if( !pArrPtr->nWhich )
537 continue;
539 if( pArrPtr->nStt >= aTmp.nEnd )
541 pArrPtr->nWhich = 0; // geloescht
542 if( !--nStackCnt )
543 break;
545 else if( pArrPtr->nEnd >= aTmp.nEnd )
547 if( ( pCmp = &pFndArr[ n ])->nWhich )
549 if( pCmp->nStt > pArrPtr->nStt ) // erweitern
550 pCmp->nStt = pArrPtr->nStt;
552 else
554 *pCmp = *pArrPtr;
555 nFound++;
557 pArrPtr->nWhich = 0;
558 if( !--nStackCnt )
559 break;
563 BOOL bContinue = FALSE;
564 if( SFX_ITEM_DONTCARE == eState )
566 // wird Attribut gueltig ?
567 if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
568 *pTmpItem ) )
570 // suche das Attribut und erweiter es gegebenenfalls
571 if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
573 *pCmp = aTmp; // nicht gefunden, eintragen
574 nFound++;
576 else if( pCmp->nStt > aTmp.nStt ) // erweitern ?
577 pCmp->nStt = aTmp.nStt;
579 bContinue = TRUE;
582 // wird Attribut gueltig ?
583 else if( CmpAttr( *pItem, *pTmpItem ))
585 pFndArr[ nWhch - nArrStart ] = aTmp;
586 ++nFound;
587 bContinue = TRUE;
590 // tja, dann muss es auf den Stack
591 if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
593 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
594 if( pCmp->nStt < aTmp.nStt )
596 ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich,
597 "Stack-Platz ist noch belegt" );
599 // ---------
600 // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
601 // pCmp->nEnd = aTmp.nStt;
602 if( aTmp.nEnd <= pCmp->nEnd )
603 pCmp->nEnd = aTmp.nStt;
604 else
605 pCmp->nStt = aTmp.nEnd;
606 // ---------
608 pStackArr[ nWhch - nArrStart ] = *pCmp;
609 nStackCnt++;
611 pCmp->nWhich = 0;
612 nFound--;
615 if( pIter )
617 nWhch = pIter->NextWhich();
618 while( nWhch &&
619 SFX_ITEM_SET != pSet->GetItemState( nWhch, TRUE, &pTmpItem ) )
620 nWhch = pIter->NextWhich();
621 if( !nWhch )
622 break;
624 else
625 break;
627 return Found();
631 xub_StrLen SwAttrCheckArr::Start() const
633 xub_StrLen nStart = nNdStt;
634 _SwSrchChrAttr* pArrPtr = pFndArr;
635 for( USHORT n = 0; n < nArrLen; ++n, ++pArrPtr )
636 if( pArrPtr->nWhich && pArrPtr->nStt > nStart )
637 nStart = pArrPtr->nStt;
639 return nStart;
643 xub_StrLen SwAttrCheckArr::End() const
645 _SwSrchChrAttr* pArrPtr = pFndArr;
646 xub_StrLen nEnd = nNdEnd;
647 for( USHORT n = 0; n < nArrLen; ++n, ++pArrPtr )
648 if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd )
649 nEnd = pArrPtr->nEnd;
651 return nEnd;
655 int SwAttrCheckArr::CheckStack()
657 if( !nStackCnt )
658 return FALSE;
660 USHORT n;
661 xub_StrLen nSttPos = Start(), nEndPos = End();
662 _SwSrchChrAttr* pArrPtr;
663 for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
665 if( !pArrPtr->nWhich )
666 continue;
668 if( bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos )
670 pArrPtr->nWhich = 0; // geloescht
671 if( !--nStackCnt )
672 return nFound == aCmpSet.Count();
674 else if( bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos )
676 // alle die "offen" sind, heisst ueber die Start Position ragen,
677 // im FndSet setzen
678 ASSERT( !pFndArr[ n ].nWhich, "Array-Platz ist noch belegt" );
679 pFndArr[ n ] = *pArrPtr;
680 pArrPtr->nWhich = 0;
681 nFound++;
682 if( !--nStackCnt )
683 return nFound == aCmpSet.Count();
686 return nFound == aCmpSet.Count();
691 int lcl_SearchForward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
692 SwPaM& rPam )
694 xub_StrLen nEndPos, nSttPos;
695 rCmpArr.SetNewSet( rTxtNd, rPam );
696 if( !rTxtNd.HasHints() )
698 if( !rCmpArr.Found() )
699 return FALSE;
700 nEndPos = rCmpArr.GetNdEnd();
701 lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, TRUE );
702 return TRUE;
705 // dann gehe mal durch das nach "Start" sortierte Array
706 const SwpHints& rHtArr = rTxtNd.GetSwpHints();
707 const SwTxtAttr* pAttr;
708 USHORT nPos = 0;
710 // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
711 // das wieder beendet wird.
712 if( rCmpArr.Found() )
714 for( ; nPos < rHtArr.Count(); ++nPos )
715 if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
717 if( rCmpArr.GetNdStt() < *pAttr->GetStart() )
719 // dann haben wir unser Ende:
720 lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
721 pAttr->GetStart(), TRUE );
722 return TRUE;
724 // ansonsten muessen wir weiter suchen
725 break;
728 if( nPos == rHtArr.Count() && rCmpArr.Found() )
730 // dann haben wir unseren Bereich
731 nEndPos = rCmpArr.GetNdEnd();
732 lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, TRUE );
733 return TRUE;
737 for( ; nPos < rHtArr.Count(); ++nPos )
738 if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
740 // sollten noch mehr auf der gleichen Position anfangen ??
741 // auch die noch mit testen !!
742 nSttPos = *pAttr->GetStart();
743 while( ++nPos < rHtArr.Count() && nSttPos ==
744 *( pAttr = rHtArr.GetStart( nPos ))->GetStart() &&
745 rCmpArr.SetAttrFwd( *pAttr ) )
747 if( !rCmpArr.Found() )
748 continue;
750 // dann haben wir den Bereich zusammen
751 if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
752 return FALSE;
753 lcl_SetAttrPam( rPam, nSttPos, &nEndPos, TRUE );
754 return TRUE;
757 if( !rCmpArr.CheckStack() ||
758 (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
759 return FALSE;
760 lcl_SetAttrPam( rPam, nSttPos, &nEndPos, TRUE );
761 return TRUE;
765 int lcl_SearchBackward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
766 SwPaM& rPam )
768 xub_StrLen nEndPos, nSttPos;
769 rCmpArr.SetNewSet( rTxtNd, rPam );
770 if( !rTxtNd.HasHints() )
772 if( !rCmpArr.Found() )
773 return FALSE;
774 nEndPos = rCmpArr.GetNdEnd();
775 lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, FALSE );
776 return TRUE;
779 // dann gehe mal durch das nach "Start" sortierte Array
780 const SwpHints& rHtArr = rTxtNd.GetSwpHints();
781 const SwTxtAttr* pAttr;
782 USHORT nPos = rHtArr.Count();
784 // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
785 // das wieder beendet wird.
786 if( rCmpArr.Found() )
788 while( nPos )
789 if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
791 nSttPos = *pAttr->GetAnyEnd();
792 if( nSttPos < rCmpArr.GetNdEnd() )
794 // dann haben wir unser Ende:
795 nEndPos = rCmpArr.GetNdEnd();
796 lcl_SetAttrPam( rPam, nSttPos, &nEndPos, FALSE );
797 return TRUE;
800 // ansonsten muessen wir weiter suchen
801 break;
804 if( !nPos && rCmpArr.Found() )
806 // dann haben wir unseren Bereich
807 nEndPos = rCmpArr.GetNdEnd();
808 lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, FALSE );
809 return TRUE;
813 while( nPos )
814 if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
816 // sollten noch mehr auf der gleichen Position anfangen ??
817 // auch die noch mit testen !!
818 if( nPos )
820 nEndPos = *pAttr->GetAnyEnd();
821 while( --nPos && nEndPos ==
822 *( pAttr = rHtArr.GetEnd( nPos ))->GetAnyEnd() &&
823 rCmpArr.SetAttrBwd( *pAttr ) )
826 if( !rCmpArr.Found() )
827 continue;
830 // dann haben wir den Bereich zusammen
831 if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
832 return FALSE;
833 lcl_SetAttrPam( rPam, nSttPos, &nEndPos, FALSE );
834 return TRUE;
837 if( !rCmpArr.CheckStack() ||
838 (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
839 return FALSE;
840 lcl_SetAttrPam( rPam, nSttPos, &nEndPos, FALSE );
841 return TRUE;
845 int lcl_Search( const SwCntntNode& rCNd, const SfxItemSet& rCmpSet, BOOL bNoColls )
847 // nur die harte Attributierung suchen ?
848 if( bNoColls && !rCNd.HasSwAttrSet() )
849 return FALSE;
851 const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
852 SfxItemIter aIter( rCmpSet );
853 const SfxPoolItem* pItem = aIter.GetCurItem();
854 const SfxPoolItem* pNdItem;
855 USHORT nWhich;
857 while( TRUE )
859 // nur testen, ob vorhanden ist ?
860 if( IsInvalidItem( pItem ))
862 nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
863 if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
864 || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
865 return FALSE;
867 else
869 nWhich = pItem->Which();
870 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
871 // runter
872 // if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
873 // || *pNdItem != *pItem )
874 if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
875 return FALSE;
878 if( aIter.IsAtEnd() )
879 break;
880 pItem = aIter.NextItem();
882 return TRUE; // wurde gefunden
886 BOOL SwPaM::Find( const SfxPoolItem& rAttr, BOOL bValue, SwMoveFn fnMove,
887 const SwPaM *pRegion, BOOL bInReadOnly )
889 // stelle fest welches Attribut gesucht wird:
890 USHORT nWhich = rAttr.Which();
891 int bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
893 SwPaM* pPam = MakeRegion( fnMove, pRegion );
895 BOOL bFound = FALSE;
896 BOOL bFirst = TRUE;
897 BOOL bSrchForward = fnMove == fnMoveForward;
898 SwCntntNode * pNode;
899 const SfxPoolItem* pItem;
900 SwpFmts aFmtArr;
902 // Wenn am Anfang/Ende, aus dem Node moven
903 if( bSrchForward
904 ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
905 : !pPam->GetPoint()->nContent.GetIndex() )
907 if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, FALSE ))
909 delete pPam;
910 return FALSE;
912 SwCntntNode *pNd = pPam->GetCntntNode();
913 xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
914 pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
917 while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
919 if( bCharAttr )
921 if( !pNode->IsTxtNode() ) // CharAttr sind nur in TextNodes
922 continue;
924 if( ((SwTxtNode*)pNode)->HasHints() &&
925 lcl_Search( *(SwTxtNode*)pNode, *pPam, rAttr, fnMove, bValue ))
927 // setze auf die Werte vom Attribut
928 SetMark();
929 *GetPoint() = *pPam->GetPoint();
930 *GetMark() = *pPam->GetMark();
931 bFound = TRUE;
932 break;
934 else if (isTXTATR(nWhich))
935 continue; // --> also weiter
938 // keine harte Attributierung, dann pruefe, ob die Vorlage schon
939 // mal nach dem Attribut befragt wurde
940 if( !pNode->HasSwAttrSet() )
942 const SwFmt* pTmpFmt = pNode->GetFmtColl();
943 if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
944 continue; // die Collection wurde schon mal befragt
945 aFmtArr.Insert( pTmpFmt );
948 if( SFX_ITEM_SET == pNode->GetSwAttrSet().GetItemState( nWhich,
949 TRUE, &pItem ) && ( !bValue || *pItem == rAttr ) )
951 // FORWARD: Point an das Ende, GetMark zum Anfanf vom Node
952 // BACKWARD: Point zum Anfang, GetMark an das Ende vom Node
953 // und immer nach der Logik: inkl. Start, exkl. End !!!
954 *GetPoint() = *pPam->GetPoint();
955 SetMark();
956 pNode->MakeEndIndex( &GetPoint()->nContent );
957 bFound = TRUE;
958 break;
962 // beim rueckwaerts Suchen noch Point und Mark vertauschen
963 if( bFound && !bSrchForward )
964 Exchange();
966 delete pPam;
967 return bFound;
971 typedef int (*FnSearchAttr)( const SwTxtNode&, SwAttrCheckArr&, SwPaM& );
973 BOOL SwPaM::Find( const SfxItemSet& rSet, BOOL bNoColls, SwMoveFn fnMove,
974 const SwPaM *pRegion, BOOL bInReadOnly, BOOL bMoveFirst )
976 SwPaM* pPam = MakeRegion( fnMove, pRegion );
978 BOOL bFound = FALSE;
979 BOOL bFirst = TRUE;
980 BOOL bSrchForward = fnMove == fnMoveForward;
981 SwCntntNode * pNode;
982 SwpFmts aFmtArr;
984 // teste doch mal welche Text/Char-Attribute gesucht werden
985 SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
986 SfxItemSet aOtherSet( GetDoc()->GetAttrPool(),
987 RES_PARATR_BEGIN, RES_GRFATR_END-1 );
988 aOtherSet.Put( rSet, FALSE ); // alle Invalid-Items erhalten!
990 FnSearchAttr fnSearch = bSrchForward
991 ? (&::lcl_SearchForward)
992 : (&::lcl_SearchBackward);
994 // Wenn am Anfang/Ende, aus dem Node moven
995 // Wenn am Anfang/Ende, aus dem Node moven
996 if( bMoveFirst &&
997 ( bSrchForward
998 ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
999 : !pPam->GetPoint()->nContent.GetIndex() ) )
1001 if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, FALSE ))
1003 delete pPam;
1004 return FALSE;
1006 SwCntntNode *pNd = pPam->GetCntntNode();
1007 xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
1008 pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
1012 while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
1014 if( aCmpArr.Count() )
1016 if( !pNode->IsTxtNode() ) // CharAttr sind nur in TextNodes
1017 continue;
1019 if( (!aOtherSet.Count() ||
1020 lcl_Search( *pNode, aOtherSet, bNoColls )) &&
1021 (*fnSearch)( *(SwTxtNode*)pNode, aCmpArr, *pPam ))
1023 // setze auf die Werte vom Attribut
1024 SetMark();
1025 *GetPoint() = *pPam->GetPoint();
1026 *GetMark() = *pPam->GetMark();
1027 bFound = TRUE;
1028 break;
1030 continue; // TextAttribute
1033 if( !aOtherSet.Count() )
1034 continue;
1036 // keine harte Attributierung, dann pruefe, ob die Vorlage schon
1037 // mal nach dem Attribut befragt wurde
1038 if( !pNode->HasSwAttrSet() )
1040 const SwFmt* pTmpFmt = pNode->GetFmtColl();
1041 if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
1042 continue; // die Collection wurde schon mal befragt
1043 aFmtArr.Insert( pTmpFmt );
1046 if( lcl_Search( *pNode, aOtherSet, bNoColls ))
1048 // FORWARD: Point an das Ende, GetMark zum Anfanf vom Node
1049 // BACKWARD: Point zum Anfang, GetMark an das Ende vom Node
1050 // und immer nach der Logik: inkl. Start, exkl. End !!!
1051 *GetPoint() = *pPam->GetPoint();
1052 SetMark();
1053 pNode->MakeEndIndex( &GetPoint()->nContent );
1054 bFound = TRUE;
1055 break;
1059 // beim rueckwaerts Suchen noch Point und Mark vertauschen
1060 if( bFound && !bSrchForward )
1061 Exchange();
1063 delete pPam;
1064 return bFound;
1067 //------------------ Methoden vom SwCursor ---------------------------
1069 // Parameter fuer das Suchen vom Attributen
1070 struct SwFindParaAttr : public SwFindParas
1072 BOOL bValue;
1073 const SfxItemSet *pSet, *pReplSet;
1074 const SearchOptions *pSearchOpt;
1075 SwCursor& rCursor;
1076 utl::TextSearch* pSTxt;
1078 SwFindParaAttr( const SfxItemSet& rSet, BOOL bNoCollection,
1079 const SearchOptions* pOpt, const SfxItemSet* pRSet,
1080 SwCursor& rCrsr )
1081 : bValue( bNoCollection ), pSet( &rSet ), pReplSet( pRSet ),
1082 pSearchOpt( pOpt ), rCursor( rCrsr ),pSTxt( 0 ) {}
1084 virtual ~SwFindParaAttr() { delete pSTxt; }
1086 virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, BOOL bInReadOnly );
1087 virtual int IsReplaceMode() const;
1091 int SwFindParaAttr::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion,
1092 BOOL bInReadOnly )
1094 // String ersetzen ?? (nur wenn Text angegeben oder nicht attributiert
1095 // gesucht wird)
1096 BOOL bReplaceTxt = pSearchOpt && ( pSearchOpt->replaceString.getLength() ||
1097 !pSet->Count() );
1098 BOOL bReplaceAttr = pReplSet && pReplSet->Count();
1099 BOOL bMoveFirst = !bReplaceAttr;
1100 if( bInReadOnly && (bReplaceAttr || bReplaceTxt ))
1101 bInReadOnly = FALSE;
1103 // wir suchen nach Attributen, soll zusaetzlich Text gesucht werden ?
1105 SwPaM aRegion( *pRegion->GetMark(), *pRegion->GetPoint() );
1106 SwPaM* pTextRegion = &aRegion;
1107 SwPaM aSrchPam( *pCrsr->GetPoint() );
1109 while( TRUE )
1111 if( pSet->Count() ) // gibts ueberhaupt Attributierung?
1113 // zuerst die Attributierung
1114 if( !aSrchPam.Find( *pSet, bValue, fnMove, &aRegion, bInReadOnly, bMoveFirst ) )
1115 //JP 17.11.95: was ist mit Attributen in leeren Absaetzen !!
1116 // || *pCrsr->GetMark() == *pCrsr->GetPoint() ) // kein Bereich ??
1117 return FIND_NOT_FOUND;
1118 bMoveFirst = TRUE;
1120 if( !pSearchOpt )
1121 break; // ok, nur Attribute, also gefunden
1123 pTextRegion = &aSrchPam;
1125 else if( !pSearchOpt )
1126 return FIND_NOT_FOUND;
1128 // dann darin den Text
1129 if( !pSTxt )
1131 SearchOptions aTmp( *pSearchOpt );
1133 // search in selection
1134 aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
1135 SearchFlags::REG_NOT_ENDOFLINE);
1137 MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aTmp.Locale );
1139 pSTxt = new utl::TextSearch( aTmp );
1142 // todo/mba: searching for attributes in Outliner text?!
1143 BOOL bSearchInNotes = FALSE;
1145 // Bug 24665: suche im richtigen Bereich weiter (pTextRegion!)
1146 if( aSrchPam.Find( *pSearchOpt, bSearchInNotes, *pSTxt, fnMove, pTextRegion, bInReadOnly ) &&
1147 *aSrchPam.GetMark() != *aSrchPam.GetPoint() ) // gefunden ?
1148 break; // also raus
1149 else if( !pSet->Count() )
1150 return FIND_NOT_FOUND; // nur Text und nicht gefunden
1152 /* // --> FME 2007-4-12 #i74765 # Why should we move the position?
1153 Moving the position results in bugs when there are two adjacent
1154 portions which both have the requested attributes set. I suspect this
1155 should be only be an optimization. Therefore I boldly remove it now!
1157 // JP: und wieder neu aufsetzen, aber eine Position weiter
1158 //JP 04.11.97: Bug 44897 - aber den Mark wieder aufheben, damit
1159 // weiterbewegt werden kann!
1161 BOOL bCheckRegion = TRUE;
1162 SwPosition* pPos = aSrchPam.GetPoint();
1163 if( !(*fnMove->fnNd)( &pPos->nNode.GetNode(),
1164 &pPos->nContent, CRSR_SKIP_CHARS ))
1166 if( (*fnMove->fnNds)( &pPos->nNode, FALSE ))
1168 SwCntntNode *pNd = pPos->nNode.GetNode().GetCntntNode();
1169 xub_StrLen nCPos;
1170 if( fnMove == fnMoveForward )
1171 nCPos = 0;
1172 else
1173 nCPos = pNd->Len();
1174 pPos->nContent.Assign( pNd, nCPos );
1176 else
1177 bCheckRegion = FALSE;
1179 if( !bCheckRegion || *aRegion.GetPoint() <= *pPos )
1180 return FIND_NOT_FOUND; // nicht gefunden
1182 *aRegion.GetMark() = *aSrchPam.GetPoint();
1185 *pCrsr->GetPoint() = *aSrchPam.GetPoint();
1186 pCrsr->SetMark();
1187 *pCrsr->GetMark() = *aSrchPam.GetMark();
1190 if( bReplaceTxt )
1192 const bool bRegExp(
1193 SearchAlgorithms_REGEXP == pSearchOpt->algorithmType);
1194 SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
1195 xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
1197 // damit die Region auch verschoben wird, in den Shell-Cursr-Ring
1198 // mit aufnehmen !!
1199 Ring *pPrevRing = 0;
1200 if( bRegExp )
1202 pPrevRing = pRegion->GetPrev();
1203 ((Ring*)pRegion)->MoveRingTo( &rCursor );
1206 ::std::auto_ptr<String> pRepl( (bRegExp) ?
1207 ReplaceBackReferences( *pSearchOpt, pCrsr ) : 0 );
1208 rCursor.GetDoc()->ReplaceRange( *pCrsr,
1209 (pRepl.get()) ? *pRepl : String(pSearchOpt->replaceString),
1210 bRegExp );
1211 rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
1213 if( bRegExp )
1215 // und die Region wieder herausnehmen:
1216 Ring *p, *pNext = (Ring*)pRegion;
1217 do {
1218 p = pNext;
1219 pNext = p->GetNext();
1220 p->MoveTo( (Ring*)pRegion );
1221 } while( p != pPrevRing );
1223 rSttCntIdx = nSttCnt;
1226 if( bReplaceAttr )
1228 // --- Ist die Selection noch da ??????
1230 // und noch die Attribute setzen
1231 #ifdef OLD
1232 pCrsr->GetDoc()->Insert( *pCrsr, *pReplSet, 0 );
1233 #else
1234 //JP 13.07.95: alle gesuchten Attribute werden, wenn nicht im
1235 // ReplaceSet angegeben, auf Default zurueck gesetzt
1237 if( !pSet->Count() )
1239 pCrsr->GetDoc()->InsertItemSet( *pCrsr, *pReplSet, 0 );
1241 else
1243 SfxItemPool* pPool = pReplSet->GetPool();
1244 SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
1246 SfxItemIter aIter( *pSet );
1247 const SfxPoolItem* pItem = aIter.GetCurItem();
1248 while( TRUE )
1250 // alle die nicht gesetzt sind mit Pool-Defaults aufuellen
1251 if( !IsInvalidItem( pItem ) && SFX_ITEM_SET !=
1252 pReplSet->GetItemState( pItem->Which(), FALSE ))
1253 aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
1255 if( aIter.IsAtEnd() )
1256 break;
1257 pItem = aIter.NextItem();
1259 aSet.Put( *pReplSet );
1260 pCrsr->GetDoc()->InsertItemSet( *pCrsr, aSet, 0 );
1262 #endif
1263 return FIND_NO_RING;
1266 else
1267 return FIND_FOUND;
1271 int SwFindParaAttr::IsReplaceMode() const
1273 return ( pSearchOpt && pSearchOpt->replaceString.getLength() ) ||
1274 ( pReplSet && pReplSet->Count() );
1277 // Suchen nach Attributen
1280 ULONG SwCursor::Find( const SfxItemSet& rSet, BOOL bNoCollections,
1281 SwDocPositions nStart, SwDocPositions nEnde, BOOL& bCancel,
1282 FindRanges eFndRngs,
1283 const SearchOptions* pSearchOpt, const SfxItemSet* pReplSet )
1285 // OLE-Benachrichtigung abschalten !!
1286 SwDoc* pDoc = GetDoc();
1287 Link aLnk( pDoc->GetOle2Link() );
1288 pDoc->SetOle2Link( Link() );
1290 BOOL bReplace = ( pSearchOpt && ( pSearchOpt->replaceString.getLength() ||
1291 !rSet.Count() ) ) ||
1292 (pReplSet && pReplSet->Count());
1293 BOOL bSttUndo = pDoc->DoesUndo() && bReplace;
1294 if( bSttUndo )
1295 pDoc->StartUndo( UNDO_REPLACE, NULL );
1297 SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
1298 pReplSet, *this );
1300 ULONG nRet = FindAll(aSwFindParaAttr, nStart, nEnde, eFndRngs, bCancel );
1301 pDoc->SetOle2Link( aLnk );
1302 if( nRet && bReplace )
1303 pDoc->SetModified();
1305 if( bSttUndo )
1306 pDoc->EndUndo( UNDO_REPLACE, NULL );
1308 return nRet;