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