xref: /aoo41x/main/sw/source/core/crsr/findattr.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <com/sun/star/lang/Locale.hpp>
29 #include <com/sun/star/util/SearchOptions.hpp>
30 #include <com/sun/star/util/SearchFlags.hpp>
31 #include <i18npool/mslangid.hxx>
32 #include <hintids.hxx>
33 #include <vcl/svapp.hxx>
34 #include <svl/itemiter.hxx>
35 #include <svl/whiter.hxx>
36 #include <editeng/brkitem.hxx>
37 #include <editeng/colritem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <fmtpdsc.hxx>
40 #include <txatbase.hxx>
41 #include <fchrfmt.hxx>
42 #include <charfmt.hxx>
43 #include <doc.hxx>
44 #include <IDocumentUndoRedo.hxx>
45 #include <swcrsr.hxx>
46 #include <editsh.hxx>
47 #include <ndtxt.hxx>
48 #include <pamtyp.hxx>
49 #include <swundo.hxx>
50 #include <crsskip.hxx>
51 
52 
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::lang;
55 using namespace ::com::sun::star::util;
56 
57 SV_DECL_PTRARR_SORT( SwpFmts, SwFmt*, 0, 4 )
58 SV_IMPL_PTRARR_SORT( SwpFmts, SwFmt* )
59 
60 	// Sonderbehandlung fuer SvxFontItem, nur den Namen vergleichen:
61 int CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 )
62 {
63 	switch( rItem1.Which() )
64 	{
65 	case RES_CHRATR_FONT:
66 		return ((SvxFontItem&)rItem1).GetFamilyName() ==
67 				((SvxFontItem&)rItem2).GetFamilyName();
68 
69 	case RES_CHRATR_COLOR:
70 		return ((SvxColorItem&)rItem1).GetValue().IsRGBEqual(
71 								((SvxColorItem&)rItem2).GetValue() );
72 	case RES_PAGEDESC:
73 		return ((SwFmtPageDesc&)rItem1).GetNumOffset() ==
74 						((SwFmtPageDesc&)rItem2).GetNumOffset() &&
75 				((SwFmtPageDesc&)rItem1).GetPageDesc() ==
76 						((SwFmtPageDesc&)rItem2).GetPageDesc();
77 	}
78 	return rItem1 == rItem2;
79 }
80 
81 
82 const SwTxtAttr* GetFrwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
83 									xub_StrLen nCntntPos )
84 {
85 	while( rPos < rHtsArr.Count() )
86 	{
87 		const SwTxtAttr *pTxtHt = rHtsArr.GetStart( rPos++ );
88 		// der Start vom Attribut muss innerhalb des Bereiches liegen !!
89 		if( *pTxtHt->GetStart() >= nCntntPos )
90 			return pTxtHt; 		// gueltiges TextAttribut
91 	}
92 	return 0;			 		// kein gueltiges TextAttribut
93 }
94 
95 
96 const SwTxtAttr* GetBkwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
97 								  xub_StrLen nCntntPos )
98 {
99 	while( rPos > 0 )
100 	{
101 		//Hack mit cast fuer das Update
102 		const SwTxtAttr *pTxtHt = rHtsArr.GetStart( --rPos );
103 		// der Start vom Attribut muss innerhalb des Bereiches liegen !!
104 		if( *pTxtHt->GetStart() < nCntntPos )
105 			return pTxtHt; 		// gueltiges TextAttribut
106 	}
107 	return 0; 					// kein gueltiges TextAttribut
108 }
109 
110 
111 void lcl_SetAttrPam( SwPaM & rPam, xub_StrLen nStart, const xub_StrLen* pEnde,
112 						const sal_Bool bSaveMark )
113 {
114 	xub_StrLen nCntntPos;
115 	if( bSaveMark )
116 		nCntntPos = rPam.GetMark()->nContent.GetIndex();
117 	else
118 		nCntntPos = rPam.GetPoint()->nContent.GetIndex();
119 	sal_Bool bTstEnde = rPam.GetPoint()->nNode == rPam.GetMark()->nNode;
120 
121 	SwCntntNode* pCNd = rPam.GetCntntNode();
122 	rPam.GetPoint()->nContent.Assign( pCNd, nStart );
123 	rPam.SetMark(); 	// Point == GetMark
124 
125 	// Point zeigt auf das Ende vom SuchBereich oder Ende vom Attribut
126 	if( pEnde )
127 	{
128 		if( bTstEnde && *pEnde > nCntntPos )
129 			rPam.GetPoint()->nContent = nCntntPos;
130 		else
131 			rPam.GetPoint()->nContent = *pEnde;
132 	}
133 }
134 
135 //------------------ Suche nach einem Text Attribut -----------------------
136 
137 // diese Funktion sucht in einem TextNode nach dem vorgegebenen Attribut.
138 // Wird es gefunden, dann hat der SwPaM den Bereich der das Attribut
139 // umspannt, unter Beachtung des Suchbereiches
140 
141 
142 sal_Bool lcl_Search( const SwTxtNode& rTxtNd, SwPaM& rPam,
143 					const SfxPoolItem& rCmpItem,
144 					SwMoveFn fnMove, sal_Bool bValue )
145 {
146 	if ( !rTxtNd.HasHints() )
147 		return sal_False;
148 	const SwTxtAttr *pTxtHt = 0;
149 	sal_Bool bForward = fnMove == fnMoveForward;
150 	sal_uInt16 nPos = bForward ? 0 : rTxtNd.GetSwpHints().Count();
151 	xub_StrLen nCntntPos = rPam.GetPoint()->nContent.GetIndex();
152 
153 	while( 0 != ( pTxtHt=(*fnMove->fnGetHint)(rTxtNd.GetSwpHints(),nPos,nCntntPos)))
154 		if( pTxtHt->Which() == rCmpItem.Which() &&
155 			( !bValue || CmpAttr( pTxtHt->GetAttr(), rCmpItem )))
156 		{
157 			lcl_SetAttrPam( rPam, *pTxtHt->GetStart(), pTxtHt->GetEnd(), bForward );
158 			return sal_True;
159 		}
160 	return sal_False;
161 }
162 
163 
164 //------------------ Suche nach mehren Text Attributen -------------------
165 
166 struct _SwSrchChrAttr
167 {
168 	sal_uInt16 nWhich;
169 	xub_StrLen nStt, nEnd;
170 
171 	_SwSrchChrAttr( const SfxPoolItem& rItem,
172 					xub_StrLen nStart, xub_StrLen nAnyEnd )
173 		: nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd )
174 	{}
175 };
176 
177 class SwAttrCheckArr
178 {
179 	_SwSrchChrAttr *pFndArr, *pStackArr;
180 	xub_StrLen nNdStt, nNdEnd;
181 	sal_uInt16 nArrStart, nArrLen;
182 	sal_uInt16 nFound, nStackCnt;
183 	SfxItemSet aCmpSet;
184 	sal_Bool bNoColls;
185 	sal_Bool bForward;
186 
187 public:
188 	SwAttrCheckArr( const SfxItemSet& rSet, int bForward, int bNoCollections );
189 	~SwAttrCheckArr();
190 
191 	void SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam );
192 
193 	// wieviele Attribute ueberhaupt ??
194 	sal_uInt16 Count() const 	{ return aCmpSet.Count(); }
195 	int Found() const 		{ return nFound == aCmpSet.Count(); }
196 	int CheckStack();
197 
198 	xub_StrLen Start() const;
199 	xub_StrLen End() const;
200 
201 	xub_StrLen GetNdStt() const { return nNdStt; }
202 	xub_StrLen GetNdEnd() const { return nNdEnd; }
203 
204 	int SetAttrFwd( const SwTxtAttr& rAttr );
205 	int SetAttrBwd( const SwTxtAttr& rAttr );
206 };
207 
208 
209 
210 SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet& rSet, int bFwd,
211 								int bNoCollections )
212 	: aCmpSet( *rSet.GetPool(), RES_CHRATR_BEGIN, RES_TXTATR_END-1 )
213 {
214 	aCmpSet.Put( rSet, sal_False );
215 	bNoColls = 0 != bNoCollections;
216 
217 	bForward = 0 != bFwd;
218 
219 	// Bestimmen den Bereich des Fnd/Stack-Arrays (Min/Max)
220 	SfxItemIter aIter( aCmpSet );
221 	nArrStart = aCmpSet.GetWhichByPos( aIter.GetFirstPos() );
222 	nArrLen = aCmpSet.GetWhichByPos( aIter.GetLastPos() ) - nArrStart+1;
223 
224     char* pFndChar  = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
225     char* pStackChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
226 
227     pFndArr = (_SwSrchChrAttr*)pFndChar;
228     pStackArr = (_SwSrchChrAttr*)pStackChar;
229 }
230 
231 SwAttrCheckArr::~SwAttrCheckArr()
232 {
233     delete[] (char*)pFndArr;
234     delete[] (char*)pStackArr;
235 }
236 
237 void SwAttrCheckArr::SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam )
238 {
239 	memset( pFndArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
240 	memset( pStackArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
241 	nFound = 0;
242 	nStackCnt = 0;
243 
244 	if( bForward )
245 	{
246 		nNdStt = rPam.GetPoint()->nContent.GetIndex();
247 		nNdEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
248 				? rPam.GetMark()->nContent.GetIndex()
249 				: rTxtNd.GetTxt().Len();
250 	}
251 	else
252 	{
253 		nNdEnd = rPam.GetPoint()->nContent.GetIndex();
254 		nNdStt = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
255 				? rPam.GetMark()->nContent.GetIndex()
256 				: 0;
257 	}
258 
259     if( bNoColls && !rTxtNd.HasSwAttrSet() )
260 		return ;
261 
262 	const SfxItemSet& rSet = rTxtNd.GetSwAttrSet();
263 //	if( !rSet.Count() )
264 //		return;
265 
266 	SfxItemIter aIter( aCmpSet );
267 	const SfxPoolItem* pItem = aIter.GetCurItem();
268 	const SfxPoolItem* pFndItem;
269 	sal_uInt16 nWhich;
270 
271 	while( sal_True )
272 	{
273 		// nur testen, ob vorhanden ist ?
274 		if( IsInvalidItem( pItem ) )
275 		{
276 			nWhich = aCmpSet.GetWhichByPos( aIter.GetCurPos() );
277 			if( RES_TXTATR_END <= nWhich )
278 				break;				// Ende der TextAttribute
279 
280 			if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
281 				&& !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) ))
282 			{
283 				pFndArr[ nWhich - nArrStart ] =
284 					_SwSrchChrAttr( *pFndItem, nNdStt, nNdEnd );
285 				nFound++;
286 			}
287 		}
288 		else
289 		{
290 			if( RES_TXTATR_END <= (nWhich = pItem->Which() ))
291 				break;				// Ende der TextAttribute
292 
293 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
294 //				runter
295 //			if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
296 //                && *pFndItem == *pItem )
297 			if( CmpAttr( rSet.Get( nWhich, !bNoColls ), *pItem ) )
298 			{
299 				pFndArr[ nWhich - nArrStart ] =
300 					_SwSrchChrAttr( *pItem, nNdStt, nNdEnd );
301 				nFound++;
302 			}
303 		}
304 
305 		if( aIter.IsAtEnd() )
306 			break;
307 		pItem = aIter.NextItem();
308 	}
309 }
310 
311 static bool
312 lcl_IsAttributeIgnorable(xub_StrLen const nNdStart, xub_StrLen const nNdEnd,
313         _SwSrchChrAttr const& rTmp)
314 {
315     // #i115528#: if there is a paragraph attribute, it has been added by the
316     // SwAttrCheckArr ctor, and nFound is 1.
317     // if the paragraph is entirely covered by hints that override the paragraph
318     // attribute, then this function must find an attribute to decrement nFound!
319     // so check for an empty search range, let attributes that start/end there
320     // cover it, and hope for the best...
321     return ((nNdEnd == nNdStart)
322             ? ((rTmp.nEnd <  nNdStart) || (nNdEnd <  rTmp.nStt))
323             : ((rTmp.nEnd <= nNdStart) || (nNdEnd <= rTmp.nStt)));
324 }
325 
326 int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr& rAttr )
327 {
328 	_SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
329 
330     // ignore all attributes not in search range
331     if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
332     {
333         return Found();
334     }
335 
336 	const SfxPoolItem* pItem;
337 // --------------------------------------------------------------
338 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
339 // --------------------------------------------------------------
340 	sal_uInt16 nWhch = rAttr.Which();
341 	SfxWhichIter* pIter = NULL;
342 	const SfxPoolItem* pTmpItem = NULL;
343     const SfxItemSet* pSet = NULL;
344 	if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
345 	{
346 		if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
347 			return Found();
348         pTmpItem = NULL;
349         pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
350         if ( pSet )
351         {
352 			pIter = new SfxWhichIter( *pSet );
353 			nWhch = pIter->FirstWhich();
354 			while( nWhch &&
355 				SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
356 				nWhch = pIter->NextWhich();
357 			if( !nWhch )
358 				pTmpItem = NULL;
359         }
360 	}
361 	else
362 		pTmpItem = &rAttr.GetAttr();
363 	while( pTmpItem )
364 	{
365 		SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
366 		if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
367 		{
368 			sal_uInt16 n;
369 			_SwSrchChrAttr* pCmp;
370 
371 			// loesche erstmal alle, die bis zu der Start Position schon wieder
372 			// ungueltig sind:
373 
374 			_SwSrchChrAttr* pArrPtr;
375 			if( nFound )
376 				for( pArrPtr = pFndArr, n = 0; n < nArrLen;
377 					++n, ++pArrPtr )
378 					if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt )
379 					{
380 						pArrPtr->nWhich = 0;		// geloescht
381 						nFound--;
382 					}
383 
384 			// loesche erstmal alle, die bis zu der Start Position schon wieder
385 			// ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
386 			// die Start Position ragen, vom Stack in den FndSet
387 
388 			if( nStackCnt )
389 				for( pArrPtr = pStackArr, n=0; n < nArrLen; ++n, ++pArrPtr )
390 				{
391 					if( !pArrPtr->nWhich )
392 						continue;
393 
394 					if( pArrPtr->nEnd <= aTmp.nStt )
395 					{
396 						pArrPtr->nWhich = 0;		// geloescht
397 						if( !--nStackCnt )
398 							break;
399 					}
400 					else if( pArrPtr->nStt <= aTmp.nStt )
401 					{
402 						if( ( pCmp = &pFndArr[ n ])->nWhich )
403 						{
404 							if( pCmp->nEnd < pArrPtr->nEnd )		// erweitern
405 								pCmp->nEnd = pArrPtr->nEnd;
406 						}
407 						else
408 						{
409 							*pCmp = *pArrPtr;
410 							nFound++;
411 						}
412 						pArrPtr->nWhich = 0;
413 						if( !--nStackCnt )
414 							break;
415 					}
416 				}
417 
418 			sal_Bool bContinue = sal_False;
419 
420 			if( SFX_ITEM_DONTCARE == eState  )
421 			{
422 				// wird Attribut gueltig ?
423 				if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
424 					*pTmpItem ))
425 				{
426 					// suche das Attribut und erweiter es gegebenenfalls
427 					if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
428 					{
429 						*pCmp = aTmp;				// nicht gefunden, eintragen
430 						nFound++;
431 					}
432 					else if( pCmp->nEnd < aTmp.nEnd )		// erweitern ?
433 						pCmp->nEnd = aTmp.nEnd;
434 
435 					bContinue = sal_True;
436 				}
437 			}
438 			// wird Attribut gueltig ?
439 			else if(  CmpAttr( *pItem, *pTmpItem ) )
440 			{
441 				pFndArr[ nWhch - nArrStart ] = aTmp;
442 				++nFound;
443 				bContinue = sal_True;
444 			}
445 
446 			// tja, dann muss es auf den Stack
447 			if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
448 			{
449 				// vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
450 				if( pCmp->nEnd > aTmp.nEnd )
451 				{
452 					ASSERT( !pStackArr[ nWhch - nArrStart ].nWhich,
453 									"Stack-Platz ist noch belegt" );
454 
455 		// ---------
456 		// JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
457 		//			pCmp->nStt = aTmp.nEnd;
458 					if( aTmp.nStt <= pCmp->nStt )
459 						pCmp->nStt = aTmp.nEnd;
460 					else
461 						pCmp->nEnd = aTmp.nStt;
462 		// ---------
463 
464 					pStackArr[ nWhch - nArrStart ] = *pCmp;
465 					nStackCnt++;
466 				}
467 				pCmp->nWhich = 0;
468 				nFound--;
469 			}
470 		}
471 		if( pIter )
472 		{
473 			nWhch = pIter->NextWhich();
474 			while( nWhch &&
475 				SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
476 				nWhch = pIter->NextWhich();
477 			if( !nWhch )
478 				break;
479 		}
480 		else
481 			break;
482 	}
483 	return Found();
484 }
485 
486 
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 
646 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 
658 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 
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 
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 
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 
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 
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 	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 
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 
1093 	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 
1099     virtual ~SwFindParaAttr()   { delete pSTxt; }
1100 
1101 	virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
1102 	virtual int IsReplaceMode() const;
1103 };
1104 
1105 
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 
1286 int SwFindParaAttr::IsReplaceMode() const
1287 {
1288 	return ( pSearchOpt && pSearchOpt->replaceString.getLength() ) ||
1289 		   ( pReplSet && pReplSet->Count() );
1290 }
1291 
1292 // Suchen nach Attributen
1293 
1294 
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