xref: /aoo42x/main/svtools/source/edit/textdoc.cxx (revision 5900e8ec)
1*5900e8ecSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*5900e8ecSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*5900e8ecSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*5900e8ecSAndrew Rist  * distributed with this work for additional information
6*5900e8ecSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*5900e8ecSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*5900e8ecSAndrew Rist  * "License"); you may not use this file except in compliance
9*5900e8ecSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*5900e8ecSAndrew Rist  *
11*5900e8ecSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*5900e8ecSAndrew Rist  *
13*5900e8ecSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*5900e8ecSAndrew Rist  * software distributed under the License is distributed on an
15*5900e8ecSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*5900e8ecSAndrew Rist  * KIND, either express or implied.  See the License for the
17*5900e8ecSAndrew Rist  * specific language governing permissions and limitations
18*5900e8ecSAndrew Rist  * under the License.
19*5900e8ecSAndrew Rist  *
20*5900e8ecSAndrew Rist  *************************************************************/
21*5900e8ecSAndrew Rist 
22*5900e8ecSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_svtools.hxx"
26cdf0e10cSrcweir #include <textdoc.hxx>
27cdf0e10cSrcweir 
28cdf0e10cSrcweir #include <stdlib.h>
29cdf0e10cSrcweir 
30cdf0e10cSrcweir SV_IMPL_PTRARR( TextCharAttribs, TextCharAttribPtr );
31cdf0e10cSrcweir 
32cdf0e10cSrcweir 
33cdf0e10cSrcweir 
34cdf0e10cSrcweir // Vergleichmethode wird von QuickSort gerufen...
35cdf0e10cSrcweir 
36cdf0e10cSrcweir EXTERN_C
37cdf0e10cSrcweir #if defined( PM2 ) && (!defined( CSET ) && !defined ( MTW ) && !defined( WTC ))
38cdf0e10cSrcweir int _stdcall
39cdf0e10cSrcweir #else
40cdf0e10cSrcweir #ifdef WNT
41cdf0e10cSrcweir #if _MSC_VER >= 1200
42cdf0e10cSrcweir int __cdecl
43cdf0e10cSrcweir #else
44cdf0e10cSrcweir int _cdecl
45cdf0e10cSrcweir #endif
46cdf0e10cSrcweir #else
47cdf0e10cSrcweir int
48cdf0e10cSrcweir #endif
49cdf0e10cSrcweir #endif
50cdf0e10cSrcweir 
51cdf0e10cSrcweir CompareStart( const void* pFirst, const void* pSecond )
52cdf0e10cSrcweir {
53cdf0e10cSrcweir 	if ( (*((TextCharAttrib**)pFirst))->GetStart() < (*((TextCharAttrib**)pSecond))->GetStart() )
54cdf0e10cSrcweir 		return (-1);
55cdf0e10cSrcweir 	else if ( (*((TextCharAttrib**)pFirst))->GetStart() > (*((TextCharAttrib**)pSecond))->GetStart() )
56cdf0e10cSrcweir 		return (1);
57cdf0e10cSrcweir 	return 0;
58cdf0e10cSrcweir }
59cdf0e10cSrcweir 
60cdf0e10cSrcweir 
61cdf0e10cSrcweir // -------------------------------------------------------------------------
62cdf0e10cSrcweir // (+) class TextCharAttrib
63cdf0e10cSrcweir // -------------------------------------------------------------------------
64cdf0e10cSrcweir TextCharAttrib::TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd )
65cdf0e10cSrcweir {
66cdf0e10cSrcweir 	mpAttr = rAttr.Clone();
67cdf0e10cSrcweir 	mnStart = nStart,
68cdf0e10cSrcweir 	mnEnd = nEnd;
69cdf0e10cSrcweir }
70cdf0e10cSrcweir 
71cdf0e10cSrcweir TextCharAttrib::TextCharAttrib( const TextCharAttrib& rTextCharAttrib )
72cdf0e10cSrcweir {
73cdf0e10cSrcweir 	mpAttr = rTextCharAttrib.GetAttr().Clone();
74cdf0e10cSrcweir 	mnStart = rTextCharAttrib.mnStart;
75cdf0e10cSrcweir 	mnEnd = rTextCharAttrib.mnEnd;
76cdf0e10cSrcweir }
77cdf0e10cSrcweir 
78cdf0e10cSrcweir TextCharAttrib::~TextCharAttrib()
79cdf0e10cSrcweir {
80cdf0e10cSrcweir 	delete mpAttr;
81cdf0e10cSrcweir }
82cdf0e10cSrcweir 
83cdf0e10cSrcweir // -------------------------------------------------------------------------
84cdf0e10cSrcweir // (+) class TextCharAttribList
85cdf0e10cSrcweir // -------------------------------------------------------------------------
86cdf0e10cSrcweir 
87cdf0e10cSrcweir TextCharAttribList::TextCharAttribList()
88cdf0e10cSrcweir {
89cdf0e10cSrcweir 	mbHasEmptyAttribs = sal_False;
90cdf0e10cSrcweir }
91cdf0e10cSrcweir 
92cdf0e10cSrcweir TextCharAttribList::~TextCharAttribList()
93cdf0e10cSrcweir {
94cdf0e10cSrcweir 	// PTRARR_DEL
95cdf0e10cSrcweir }
96cdf0e10cSrcweir 
97cdf0e10cSrcweir void TextCharAttribList::Clear( sal_Bool bDestroyAttribs )
98cdf0e10cSrcweir {
99cdf0e10cSrcweir 	if ( bDestroyAttribs )
100cdf0e10cSrcweir 		TextCharAttribs::DeleteAndDestroy( 0, Count() );
101cdf0e10cSrcweir 	else
102cdf0e10cSrcweir 		TextCharAttribs::Remove( 0, Count() );
103cdf0e10cSrcweir }
104cdf0e10cSrcweir 
105cdf0e10cSrcweir 
106cdf0e10cSrcweir void TextCharAttribList::InsertAttrib( TextCharAttrib* pAttrib )
107cdf0e10cSrcweir {
108cdf0e10cSrcweir 	if ( pAttrib->IsEmpty() )
109cdf0e10cSrcweir 		mbHasEmptyAttribs = sal_True;
110cdf0e10cSrcweir 
111cdf0e10cSrcweir 	const sal_uInt16 nCount = Count();
112cdf0e10cSrcweir 	const sal_uInt16 nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt.
113cdf0e10cSrcweir 	sal_Bool bInserted = sal_False;
114cdf0e10cSrcweir 	for ( sal_uInt16 x = 0; x < nCount; x++ )
115cdf0e10cSrcweir 	{
116cdf0e10cSrcweir 		TextCharAttrib* pCurAttrib = GetObject( x );
117cdf0e10cSrcweir 		if ( pCurAttrib->GetStart() > nStart )
118cdf0e10cSrcweir 		{
119cdf0e10cSrcweir 			Insert( pAttrib, x );
120cdf0e10cSrcweir 			bInserted = sal_True;
121cdf0e10cSrcweir 			break;
122cdf0e10cSrcweir 		}
123cdf0e10cSrcweir 	}
124cdf0e10cSrcweir 	if ( !bInserted )
125cdf0e10cSrcweir 		Insert( pAttrib, nCount );
126cdf0e10cSrcweir }
127cdf0e10cSrcweir 
128cdf0e10cSrcweir void TextCharAttribList::ResortAttribs()
129cdf0e10cSrcweir {
130cdf0e10cSrcweir 	if ( Count() )
131cdf0e10cSrcweir 		qsort( (void*)GetData(), Count(), sizeof( TextCharAttrib* ), CompareStart );
132cdf0e10cSrcweir }
133cdf0e10cSrcweir 
134cdf0e10cSrcweir TextCharAttrib* TextCharAttribList::FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
135cdf0e10cSrcweir {
136cdf0e10cSrcweir 	// Rueckwaerts, falls eins dort endet, das naechste startet.
137cdf0e10cSrcweir 	// => Das startende gilt...
138cdf0e10cSrcweir 
139cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = Count(); nAttr; )
140cdf0e10cSrcweir 	{
141cdf0e10cSrcweir 		TextCharAttrib* pAttr = GetObject( --nAttr );
142cdf0e10cSrcweir 
143cdf0e10cSrcweir 		if ( pAttr->GetEnd() < nPos )
144cdf0e10cSrcweir 			return 0;
145cdf0e10cSrcweir 
146cdf0e10cSrcweir 		if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) )
147cdf0e10cSrcweir 			return pAttr;
148cdf0e10cSrcweir 	}
149cdf0e10cSrcweir 	return NULL;
150cdf0e10cSrcweir }
151cdf0e10cSrcweir 
152cdf0e10cSrcweir TextCharAttrib* TextCharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos ) const
153cdf0e10cSrcweir {
154cdf0e10cSrcweir 	DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
155cdf0e10cSrcweir 	const sal_uInt16 nAttribs = Count();
156cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
157cdf0e10cSrcweir 	{
158cdf0e10cSrcweir 		TextCharAttrib* pAttr = GetObject( nAttr );
159cdf0e10cSrcweir 		if ( ( pAttr->GetStart() >= nFromPos ) &&
160cdf0e10cSrcweir 			 ( pAttr->GetEnd() <= nMaxPos ) &&
161cdf0e10cSrcweir 			 ( pAttr->Which() == nWhich ) )
162cdf0e10cSrcweir 			return pAttr;
163cdf0e10cSrcweir 	}
164cdf0e10cSrcweir 	return NULL;
165cdf0e10cSrcweir }
166cdf0e10cSrcweir 
167cdf0e10cSrcweir sal_Bool TextCharAttribList::HasAttrib( sal_uInt16 nWhich ) const
168cdf0e10cSrcweir {
169cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = Count(); nAttr; )
170cdf0e10cSrcweir 	{
171cdf0e10cSrcweir 		const TextCharAttrib* pAttr = GetObject( --nAttr );
172cdf0e10cSrcweir 		if ( pAttr->Which() == nWhich )
173cdf0e10cSrcweir 			return sal_True;
174cdf0e10cSrcweir 	}
175cdf0e10cSrcweir 	return sal_False;
176cdf0e10cSrcweir }
177cdf0e10cSrcweir 
178cdf0e10cSrcweir sal_Bool TextCharAttribList::HasBoundingAttrib( sal_uInt16 nBound )
179cdf0e10cSrcweir {
180cdf0e10cSrcweir 	// Rueckwaerts, falls eins dort endet, das naechste startet.
181cdf0e10cSrcweir 	// => Das startende gilt...
182cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = Count(); nAttr; )
183cdf0e10cSrcweir 	{
184cdf0e10cSrcweir 		TextCharAttrib* pAttr = GetObject( --nAttr );
185cdf0e10cSrcweir 
186cdf0e10cSrcweir 		if ( pAttr->GetEnd() < nBound )
187cdf0e10cSrcweir 			return sal_False;
188cdf0e10cSrcweir 
189cdf0e10cSrcweir 		if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) )
190cdf0e10cSrcweir 			return sal_True;
191cdf0e10cSrcweir 	}
192cdf0e10cSrcweir 	return sal_False;
193cdf0e10cSrcweir }
194cdf0e10cSrcweir 
195cdf0e10cSrcweir TextCharAttrib* TextCharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
196cdf0e10cSrcweir {
197cdf0e10cSrcweir 	if ( !mbHasEmptyAttribs )
198cdf0e10cSrcweir 		return 0;
199cdf0e10cSrcweir 
200cdf0e10cSrcweir 	const sal_uInt16 nAttribs = Count();
201cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
202cdf0e10cSrcweir 	{
203cdf0e10cSrcweir 		TextCharAttrib* pAttr = GetObject( nAttr );
204cdf0e10cSrcweir 		if ( pAttr->GetStart() > nPos )
205cdf0e10cSrcweir 			return 0;
206cdf0e10cSrcweir 
207cdf0e10cSrcweir 		if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) )
208cdf0e10cSrcweir 			return pAttr;
209cdf0e10cSrcweir 	}
210cdf0e10cSrcweir 	return 0;
211cdf0e10cSrcweir }
212cdf0e10cSrcweir 
213cdf0e10cSrcweir void TextCharAttribList::DeleteEmptyAttribs()
214cdf0e10cSrcweir {
215cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < Count(); nAttr++ )
216cdf0e10cSrcweir 	{
217cdf0e10cSrcweir 		TextCharAttrib* pAttr = GetObject( nAttr );
218cdf0e10cSrcweir 		if ( pAttr->IsEmpty() )
219cdf0e10cSrcweir 		{
220cdf0e10cSrcweir 			Remove( nAttr );
221cdf0e10cSrcweir 			delete pAttr;
222cdf0e10cSrcweir 			nAttr--;
223cdf0e10cSrcweir 		}
224cdf0e10cSrcweir 	}
225cdf0e10cSrcweir 	mbHasEmptyAttribs = sal_False;
226cdf0e10cSrcweir }
227cdf0e10cSrcweir 
228cdf0e10cSrcweir #ifdef  DBG_UTIL
229cdf0e10cSrcweir sal_Bool TextCharAttribList::DbgCheckAttribs()
230cdf0e10cSrcweir {
231cdf0e10cSrcweir 	sal_Bool bOK = sal_True;
232cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < Count(); nAttr++ )
233cdf0e10cSrcweir 	{
234cdf0e10cSrcweir 		TextCharAttrib* pAttr = GetObject( nAttr );
235cdf0e10cSrcweir 		if ( pAttr->GetStart() > pAttr->GetEnd() )
236cdf0e10cSrcweir 		{
237cdf0e10cSrcweir 			bOK = sal_False;
238cdf0e10cSrcweir 			DBG_ERROR( "Attr verdreht" );
239cdf0e10cSrcweir 		}
240cdf0e10cSrcweir 	}
241cdf0e10cSrcweir 	return bOK;
242cdf0e10cSrcweir }
243cdf0e10cSrcweir #endif
244cdf0e10cSrcweir 
245cdf0e10cSrcweir // -------------------------------------------------------------------------
246cdf0e10cSrcweir // (+) class TextNode
247cdf0e10cSrcweir // -------------------------------------------------------------------------
248cdf0e10cSrcweir 
249cdf0e10cSrcweir TextNode::TextNode( const String& rText ) :
250cdf0e10cSrcweir 	maText( rText )
251cdf0e10cSrcweir {
252cdf0e10cSrcweir }
253cdf0e10cSrcweir 
254cdf0e10cSrcweir void TextNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew )
255cdf0e10cSrcweir {
256cdf0e10cSrcweir 	if ( !nNew )
257cdf0e10cSrcweir 		return;
258cdf0e10cSrcweir 
259cdf0e10cSrcweir 	sal_Bool bResort = sal_False;
260cdf0e10cSrcweir 	sal_uInt16 nAttribs = maCharAttribs.Count();
261cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
262cdf0e10cSrcweir 	{
263cdf0e10cSrcweir 		TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
264cdf0e10cSrcweir 		if ( pAttrib->GetEnd() >= nIndex )
265cdf0e10cSrcweir 		{
266cdf0e10cSrcweir 			// Alle Attribute hinter der Einfuegeposition verschieben...
267cdf0e10cSrcweir 			if ( pAttrib->GetStart() > nIndex )
268cdf0e10cSrcweir 			{
269cdf0e10cSrcweir 				pAttrib->MoveForward( nNew );
270cdf0e10cSrcweir 			}
271cdf0e10cSrcweir 			// 0: Leeres Attribut expandieren, wenn an Einfuegestelle
272cdf0e10cSrcweir 			else if ( pAttrib->IsEmpty() )
273cdf0e10cSrcweir 			{
274cdf0e10cSrcweir 				// Index nicht pruefen, leeres durfte nur dort liegen.
275cdf0e10cSrcweir 				// Wenn spaeter doch Ueberpruefung:
276cdf0e10cSrcweir 				//   Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch!
277cdf0e10cSrcweir 				// Start <= nIndex, End >= nIndex => Start=End=nIndex!
278cdf0e10cSrcweir //				if ( pAttrib->GetStart() == nIndex )
279cdf0e10cSrcweir 					pAttrib->Expand( nNew );
280cdf0e10cSrcweir 			}
281cdf0e10cSrcweir 			// 1: Attribut startet davor, geht bis Index...
282cdf0e10cSrcweir 			else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen
283cdf0e10cSrcweir 			{
284cdf0e10cSrcweir 				// Nur expandieren, wenn kein Feature,
285cdf0e10cSrcweir 				// und wenn nicht in ExcludeListe!
286cdf0e10cSrcweir 				// Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren
287cdf0e10cSrcweir 				if ( !maCharAttribs.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
288cdf0e10cSrcweir 				{
289cdf0e10cSrcweir 					pAttrib->Expand( nNew );
290cdf0e10cSrcweir 				}
291cdf0e10cSrcweir 				else
292cdf0e10cSrcweir 					bResort = sal_True;
293cdf0e10cSrcweir 			}
294cdf0e10cSrcweir 			// 2: Attribut startet davor, geht hinter Index...
295cdf0e10cSrcweir 			else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
296cdf0e10cSrcweir 			{
297cdf0e10cSrcweir 				pAttrib->Expand( nNew );
298cdf0e10cSrcweir 			}
299cdf0e10cSrcweir 			// 3: Attribut startet auf Index...
300cdf0e10cSrcweir 			else if ( pAttrib->GetStart() == nIndex )
301cdf0e10cSrcweir 			{
302cdf0e10cSrcweir 				if ( nIndex == 0 )
303cdf0e10cSrcweir 				{
304cdf0e10cSrcweir 					pAttrib->Expand( nNew );
305cdf0e10cSrcweir //					bResort = sal_True;		// es gibt ja keine Features mehr...
306cdf0e10cSrcweir 				}
307cdf0e10cSrcweir 				else
308cdf0e10cSrcweir 					pAttrib->MoveForward( nNew );
309cdf0e10cSrcweir 			}
310cdf0e10cSrcweir 		}
311cdf0e10cSrcweir 
312cdf0e10cSrcweir 		DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" );
313cdf0e10cSrcweir 		DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len() ), "Expand: Attrib groesser als Absatz!" );
314cdf0e10cSrcweir 		DBG_ASSERT( !pAttrib->IsEmpty(), "Leeres Attribut nach ExpandAttribs?" );
315cdf0e10cSrcweir 	}
316cdf0e10cSrcweir 
317cdf0e10cSrcweir 	if ( bResort )
318cdf0e10cSrcweir 		maCharAttribs.ResortAttribs();
319cdf0e10cSrcweir 
320cdf0e10cSrcweir #ifdef EDITDEBUG
321cdf0e10cSrcweir 	DBG_ASSERT( CheckOrderedList( (TextCharAttribs*)&maCharAttribs ), "Expand: Start-Liste verdreht" );
322cdf0e10cSrcweir #endif
323cdf0e10cSrcweir }
324cdf0e10cSrcweir 
325cdf0e10cSrcweir void TextNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted )
326cdf0e10cSrcweir {
327cdf0e10cSrcweir 	if ( !nDeleted )
328cdf0e10cSrcweir 		return;
329cdf0e10cSrcweir 
330cdf0e10cSrcweir 	sal_Bool bResort = sal_False;
331cdf0e10cSrcweir 	sal_uInt16 nEndChanges = nIndex+nDeleted;
332cdf0e10cSrcweir 
333cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
334cdf0e10cSrcweir 	{
335cdf0e10cSrcweir 		TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
336cdf0e10cSrcweir 		sal_Bool bDelAttr = sal_False;
337cdf0e10cSrcweir 		if ( pAttrib->GetEnd() >= nIndex )
338cdf0e10cSrcweir 		{
339cdf0e10cSrcweir 			// Alles Attribute hinter der Einfuegeposition verschieben...
340cdf0e10cSrcweir 			if ( pAttrib->GetStart() >= nEndChanges )
341cdf0e10cSrcweir 			{
342cdf0e10cSrcweir 				pAttrib->MoveBackward( nDeleted );
343cdf0e10cSrcweir 			}
344cdf0e10cSrcweir 			// 1. Innenliegende Attribute loeschen...
345cdf0e10cSrcweir 			else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
346cdf0e10cSrcweir 			{
347cdf0e10cSrcweir 				// Spezialfall: Attrubt deckt genau den Bereich ab
348cdf0e10cSrcweir 				// => als leeres Attribut behalten.
349cdf0e10cSrcweir 				if ( ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
350cdf0e10cSrcweir 					pAttrib->GetEnd() = nIndex;	// leer
351cdf0e10cSrcweir 				else
352cdf0e10cSrcweir 					bDelAttr = sal_True;
353cdf0e10cSrcweir 			}
354cdf0e10cSrcweir 			// 2. Attribut beginnt davor, endet drinnen oder dahinter...
355cdf0e10cSrcweir 			else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
356cdf0e10cSrcweir 			{
357cdf0e10cSrcweir 				if ( pAttrib->GetEnd() <= nEndChanges )	// endet drinnen
358cdf0e10cSrcweir 					pAttrib->GetEnd() = nIndex;
359cdf0e10cSrcweir 				else
360cdf0e10cSrcweir 					pAttrib->Collaps( nDeleted );		// endet dahinter
361cdf0e10cSrcweir 			}
362cdf0e10cSrcweir 			// 3. Attribut beginnt drinnen, endet dahinter...
363cdf0e10cSrcweir 			else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
364cdf0e10cSrcweir 			{
365cdf0e10cSrcweir 				// Features duerfen nicht expandieren!
366cdf0e10cSrcweir 				pAttrib->GetStart() = nEndChanges;
367cdf0e10cSrcweir 				pAttrib->MoveBackward( nDeleted );
368cdf0e10cSrcweir 			}
369cdf0e10cSrcweir 		}
370cdf0e10cSrcweir 
371cdf0e10cSrcweir 		DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" );
372cdf0e10cSrcweir 		DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" );
373cdf0e10cSrcweir 		if ( bDelAttr /* || pAttrib->IsEmpty() */ )
374cdf0e10cSrcweir 		{
375cdf0e10cSrcweir 			bResort = sal_True;
376cdf0e10cSrcweir 			maCharAttribs.RemoveAttrib( nAttr );
377cdf0e10cSrcweir 			delete pAttrib;
378cdf0e10cSrcweir 			nAttr--;
379cdf0e10cSrcweir 		}
380cdf0e10cSrcweir 		else if ( pAttrib->IsEmpty() )
381cdf0e10cSrcweir 			maCharAttribs.HasEmptyAttribs() = sal_True;
382cdf0e10cSrcweir 	}
383cdf0e10cSrcweir 
384cdf0e10cSrcweir 	if ( bResort )
385cdf0e10cSrcweir 		maCharAttribs.ResortAttribs();
386cdf0e10cSrcweir 
387cdf0e10cSrcweir #ifdef EDITDEBUG
388cdf0e10cSrcweir 	DBG_ASSERT( CheckOrderedList( (TextCharAttribs)&maCharAttribs ), "Collaps: Start-Liste verdreht" );
389cdf0e10cSrcweir #endif
390cdf0e10cSrcweir }
391cdf0e10cSrcweir 
392cdf0e10cSrcweir void TextNode::InsertText( sal_uInt16 nPos, const String& rText )
393cdf0e10cSrcweir {
394cdf0e10cSrcweir 	maText.Insert( rText, nPos );
395cdf0e10cSrcweir 	ExpandAttribs( nPos, rText.Len() );
396cdf0e10cSrcweir }
397cdf0e10cSrcweir 
398cdf0e10cSrcweir void TextNode::InsertText( sal_uInt16 nPos, sal_Unicode c )
399cdf0e10cSrcweir {
400cdf0e10cSrcweir 	maText.Insert( c, nPos );
401cdf0e10cSrcweir 	ExpandAttribs( nPos, 1 );
402cdf0e10cSrcweir }
403cdf0e10cSrcweir 
404cdf0e10cSrcweir void TextNode::RemoveText( sal_uInt16 nPos, sal_uInt16 nChars )
405cdf0e10cSrcweir {
406cdf0e10cSrcweir 	maText.Erase( nPos, nChars );
407cdf0e10cSrcweir 	CollapsAttribs( nPos, nChars );
408cdf0e10cSrcweir }
409cdf0e10cSrcweir 
410cdf0e10cSrcweir TextNode* TextNode::Split( sal_uInt16 nPos, sal_Bool bKeepEndingAttribs )
411cdf0e10cSrcweir {
412cdf0e10cSrcweir 	String aNewText;
413cdf0e10cSrcweir 	if ( nPos < maText.Len() )
414cdf0e10cSrcweir 	{
415cdf0e10cSrcweir 		aNewText = maText.Copy( nPos );
416cdf0e10cSrcweir 		maText.Erase( nPos );
417cdf0e10cSrcweir 	}
418cdf0e10cSrcweir 	TextNode* pNew = new TextNode( aNewText );
419cdf0e10cSrcweir 
420cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
421cdf0e10cSrcweir 	{
422cdf0e10cSrcweir 		TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
423cdf0e10cSrcweir 		if ( pAttrib->GetEnd() < nPos )
424cdf0e10cSrcweir 		{
425cdf0e10cSrcweir 			// bleiben unveraendert....
426cdf0e10cSrcweir 			;
427cdf0e10cSrcweir 		}
428cdf0e10cSrcweir 		else if ( pAttrib->GetEnd() == nPos )
429cdf0e10cSrcweir 		{
430cdf0e10cSrcweir 			// muessen als leeres Attribut kopiert werden.
431cdf0e10cSrcweir 			// !FindAttrib nur sinnvoll, wenn Rueckwaerts durch Liste!
432cdf0e10cSrcweir 			if ( bKeepEndingAttribs && !pNew->maCharAttribs.FindAttrib( pAttrib->Which(), 0 ) )
433cdf0e10cSrcweir 			{
434cdf0e10cSrcweir 				TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
435cdf0e10cSrcweir 				pNewAttrib->GetStart() = 0;
436cdf0e10cSrcweir 				pNewAttrib->GetEnd() = 0;
437cdf0e10cSrcweir 				pNew->maCharAttribs.InsertAttrib( pNewAttrib );
438cdf0e10cSrcweir 			}
439cdf0e10cSrcweir 		}
440cdf0e10cSrcweir 		else if ( pAttrib->IsInside( nPos ) || ( !nPos && !pAttrib->GetStart() ) )
441cdf0e10cSrcweir 		{
442cdf0e10cSrcweir 			// Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben!
443cdf0e10cSrcweir 			// muessen kopiert und geaendert werden
444cdf0e10cSrcweir 			TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
445cdf0e10cSrcweir 			pNewAttrib->GetStart() = 0;
446cdf0e10cSrcweir 			pNewAttrib->GetEnd() = pAttrib->GetEnd()-nPos;
447cdf0e10cSrcweir 			pNew->maCharAttribs.InsertAttrib( pNewAttrib );
448cdf0e10cSrcweir 			// stutzen:
449cdf0e10cSrcweir 			pAttrib->GetEnd() = nPos;
450cdf0e10cSrcweir 		}
451cdf0e10cSrcweir 		else
452cdf0e10cSrcweir 		{
453cdf0e10cSrcweir 			DBG_ASSERT( pAttrib->GetStart() >= nPos, "Start < nPos!" );
454cdf0e10cSrcweir 			DBG_ASSERT( pAttrib->GetEnd() >= nPos, "End < nPos!" );
455cdf0e10cSrcweir 			// alle dahinter verschieben in den neuen Node (this)
456cdf0e10cSrcweir 			maCharAttribs.RemoveAttrib( nAttr );
457cdf0e10cSrcweir 			pNew->maCharAttribs.InsertAttrib( pAttrib );
458cdf0e10cSrcweir 			pAttrib->GetStart() = pAttrib->GetStart() - nPos;
459cdf0e10cSrcweir 			pAttrib->GetEnd() = pAttrib->GetEnd() - nPos;
460cdf0e10cSrcweir 			nAttr--;
461cdf0e10cSrcweir 		}
462cdf0e10cSrcweir 	}
463cdf0e10cSrcweir 	return pNew;
464cdf0e10cSrcweir }
465cdf0e10cSrcweir 
466cdf0e10cSrcweir void TextNode::Append( const TextNode& rNode )
467cdf0e10cSrcweir {
468cdf0e10cSrcweir 	sal_uInt16 nOldLen = maText.Len();
469cdf0e10cSrcweir 
470cdf0e10cSrcweir 	maText += rNode.GetText();
471cdf0e10cSrcweir 
472cdf0e10cSrcweir #ifdef EDITDEBUG
473cdf0e10cSrcweir 	DBG_ASSERT( maCharAttribs.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" );
474cdf0e10cSrcweir #endif
475cdf0e10cSrcweir 
476cdf0e10cSrcweir 	const sal_uInt16 nAttribs = rNode.GetCharAttribs().Count();
477cdf0e10cSrcweir 	for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
478cdf0e10cSrcweir 	{
479cdf0e10cSrcweir 		TextCharAttrib* pAttrib = rNode.GetCharAttribs().GetAttrib( nAttr );
480cdf0e10cSrcweir 		sal_Bool bMelted = sal_False;
481cdf0e10cSrcweir 		if ( pAttrib->GetStart() == 0 )
482cdf0e10cSrcweir 		{
483cdf0e10cSrcweir 			// Evtl koennen Attribute zusammengefasst werden:
484cdf0e10cSrcweir 			sal_uInt16 nTmpAttribs = maCharAttribs.Count();
485cdf0e10cSrcweir 			for ( sal_uInt16 nTmpAttr = 0; nTmpAttr < nTmpAttribs; nTmpAttr++ )
486cdf0e10cSrcweir 			{
487cdf0e10cSrcweir 				TextCharAttrib* pTmpAttrib = maCharAttribs.GetAttrib( nTmpAttr );
488cdf0e10cSrcweir 
489cdf0e10cSrcweir 				if ( pTmpAttrib->GetEnd() == nOldLen )
490cdf0e10cSrcweir 				{
491cdf0e10cSrcweir 					if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
492cdf0e10cSrcweir 						 ( pTmpAttrib->GetAttr() == pAttrib->GetAttr() ) )
493cdf0e10cSrcweir 					{
494cdf0e10cSrcweir 						pTmpAttrib->GetEnd() =
495cdf0e10cSrcweir                             pTmpAttrib->GetEnd() + pAttrib->GetLen();
496cdf0e10cSrcweir 						bMelted = sal_True;
497cdf0e10cSrcweir 						break;	// es kann nur eins von der Sorte an der Stelle geben
498cdf0e10cSrcweir 					}
499cdf0e10cSrcweir 				}
500cdf0e10cSrcweir 			}
501cdf0e10cSrcweir 		}
502cdf0e10cSrcweir 
503cdf0e10cSrcweir 		if ( !bMelted )
504cdf0e10cSrcweir 		{
505cdf0e10cSrcweir 			TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
506cdf0e10cSrcweir 			pNewAttrib->GetStart() = pNewAttrib->GetStart() + nOldLen;
507cdf0e10cSrcweir 			pNewAttrib->GetEnd() = pNewAttrib->GetEnd() + nOldLen;
508cdf0e10cSrcweir 			maCharAttribs.InsertAttrib( pNewAttrib );
509cdf0e10cSrcweir 		}
510cdf0e10cSrcweir 	}
511cdf0e10cSrcweir 
512cdf0e10cSrcweir #ifdef EDITDEBUG
513cdf0e10cSrcweir 	DBG_ASSERT( maCharAttribs.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" );
514cdf0e10cSrcweir #endif
515cdf0e10cSrcweir }
516cdf0e10cSrcweir 
517cdf0e10cSrcweir // -------------------------------------------------------------------------
518cdf0e10cSrcweir // (+) class TextDoc
519cdf0e10cSrcweir // -------------------------------------------------------------------------
520cdf0e10cSrcweir 
521cdf0e10cSrcweir TextDoc::TextDoc()
522cdf0e10cSrcweir {
523cdf0e10cSrcweir 	mnLeftMargin = 0;
524cdf0e10cSrcweir };
525cdf0e10cSrcweir 
526cdf0e10cSrcweir TextDoc::~TextDoc()
527cdf0e10cSrcweir {
528cdf0e10cSrcweir 	DestroyTextNodes();
529cdf0e10cSrcweir }
530cdf0e10cSrcweir 
531cdf0e10cSrcweir void TextDoc::Clear()
532cdf0e10cSrcweir {
533cdf0e10cSrcweir 	DestroyTextNodes();
534cdf0e10cSrcweir }
535cdf0e10cSrcweir 
536cdf0e10cSrcweir void TextDoc::DestroyTextNodes()
537cdf0e10cSrcweir {
538cdf0e10cSrcweir 	for ( sal_uLong nNode = 0; nNode < maTextNodes.Count(); nNode++ )
539cdf0e10cSrcweir 		delete maTextNodes.GetObject( nNode );
540cdf0e10cSrcweir 	maTextNodes.clear();
541cdf0e10cSrcweir }
542cdf0e10cSrcweir 
543cdf0e10cSrcweir String TextDoc::GetText( const sal_Unicode* pSep ) const
544cdf0e10cSrcweir {
545cdf0e10cSrcweir 	sal_uLong nLen = GetTextLen( pSep );
546cdf0e10cSrcweir 	sal_uLong nNodes = maTextNodes.Count();
547cdf0e10cSrcweir 
548cdf0e10cSrcweir 	if ( nLen > STRING_MAXLEN )
549cdf0e10cSrcweir 	{
550cdf0e10cSrcweir 		DBG_ERROR( "Text zu gross fuer String" );
551cdf0e10cSrcweir 		return String();
552cdf0e10cSrcweir 	}
553cdf0e10cSrcweir 
554cdf0e10cSrcweir 	String aASCIIText;
555cdf0e10cSrcweir 	sal_uLong nLastNode = nNodes-1;
556cdf0e10cSrcweir 	for ( sal_uLong nNode = 0; nNode < nNodes; nNode++ )
557cdf0e10cSrcweir 	{
558cdf0e10cSrcweir 		TextNode* pNode = maTextNodes.GetObject( nNode );
559cdf0e10cSrcweir 		String aTmp( pNode->GetText() );
560cdf0e10cSrcweir 		aASCIIText += aTmp;
561cdf0e10cSrcweir 		if ( pSep && ( nNode != nLastNode ) )
562cdf0e10cSrcweir 			aASCIIText += pSep;
563cdf0e10cSrcweir 	}
564cdf0e10cSrcweir 
565cdf0e10cSrcweir 	return aASCIIText;
566cdf0e10cSrcweir }
567cdf0e10cSrcweir 
568cdf0e10cSrcweir XubString TextDoc::GetText( sal_uLong nPara ) const
569cdf0e10cSrcweir {
570cdf0e10cSrcweir 	XubString aText;
571cdf0e10cSrcweir 	TextNode* pNode = ( nPara < maTextNodes.Count() ) ? maTextNodes.GetObject( nPara ) : 0;
572cdf0e10cSrcweir 	if ( pNode )
573cdf0e10cSrcweir 		aText = pNode->GetText();
574cdf0e10cSrcweir 
575cdf0e10cSrcweir 	return aText;
576cdf0e10cSrcweir }
577cdf0e10cSrcweir 
578cdf0e10cSrcweir 
579cdf0e10cSrcweir sal_uLong TextDoc::GetTextLen( const xub_Unicode* pSep, const TextSelection* pSel ) const
580cdf0e10cSrcweir {
581cdf0e10cSrcweir 	sal_uLong nLen = 0;
582cdf0e10cSrcweir 	sal_uLong nNodes = maTextNodes.Count();
583cdf0e10cSrcweir 	if ( nNodes )
584cdf0e10cSrcweir 	{
585cdf0e10cSrcweir 		sal_uLong nStartNode = 0;
586cdf0e10cSrcweir 		sal_uLong nEndNode = nNodes-1;
587cdf0e10cSrcweir 		if ( pSel )
588cdf0e10cSrcweir 		{
589cdf0e10cSrcweir 			nStartNode = pSel->GetStart().GetPara();
590cdf0e10cSrcweir 			nEndNode = pSel->GetEnd().GetPara();
591cdf0e10cSrcweir 		}
592cdf0e10cSrcweir 
593cdf0e10cSrcweir 		for ( sal_uLong nNode = nStartNode; nNode <= nEndNode; nNode++ )
594cdf0e10cSrcweir 		{
595cdf0e10cSrcweir 			TextNode* pNode = maTextNodes.GetObject( nNode );
596cdf0e10cSrcweir 
597cdf0e10cSrcweir 			sal_uInt16 nS = 0;
598cdf0e10cSrcweir 			sal_uLong nE = pNode->GetText().Len();
599cdf0e10cSrcweir 			if ( pSel && ( nNode == pSel->GetStart().GetPara() ) )
600cdf0e10cSrcweir 				nS = pSel->GetStart().GetIndex();
601cdf0e10cSrcweir 			if ( pSel && ( nNode == pSel->GetEnd().GetPara() ) )
602cdf0e10cSrcweir 				nE = pSel->GetEnd().GetIndex();
603cdf0e10cSrcweir 
604cdf0e10cSrcweir 			nLen += ( nE - nS );
605cdf0e10cSrcweir 		}
606cdf0e10cSrcweir 
607cdf0e10cSrcweir 		if ( pSep )
608cdf0e10cSrcweir 			nLen += (nEndNode-nStartNode) * String( pSep ).Len();
609cdf0e10cSrcweir 	}
610cdf0e10cSrcweir 
611cdf0e10cSrcweir 	return nLen;
612cdf0e10cSrcweir }
613cdf0e10cSrcweir 
614cdf0e10cSrcweir TextPaM TextDoc::InsertText( const TextPaM& rPaM, xub_Unicode c )
615cdf0e10cSrcweir {
616cdf0e10cSrcweir 	DBG_ASSERT( c != 0x0A, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
617cdf0e10cSrcweir 	DBG_ASSERT( c != 0x0D, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
618cdf0e10cSrcweir 
619cdf0e10cSrcweir 	TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
620cdf0e10cSrcweir 	pNode->InsertText( rPaM.GetIndex(), c );
621cdf0e10cSrcweir 
622cdf0e10cSrcweir 	TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+1 );
623cdf0e10cSrcweir 	return aPaM;
624cdf0e10cSrcweir }
625cdf0e10cSrcweir 
626cdf0e10cSrcweir TextPaM TextDoc::InsertText( const TextPaM& rPaM, const XubString& rStr )
627cdf0e10cSrcweir {
628cdf0e10cSrcweir 	DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
629cdf0e10cSrcweir 	DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
630cdf0e10cSrcweir 
631cdf0e10cSrcweir 	TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
632cdf0e10cSrcweir 	pNode->InsertText( rPaM.GetIndex(), rStr );
633cdf0e10cSrcweir 
634cdf0e10cSrcweir 	TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+rStr.Len() );
635cdf0e10cSrcweir 	return aPaM;
636cdf0e10cSrcweir }
637cdf0e10cSrcweir 
638cdf0e10cSrcweir TextPaM TextDoc::InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs )
639cdf0e10cSrcweir {
640cdf0e10cSrcweir 	TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
641cdf0e10cSrcweir 	TextNode* pNew = pNode->Split( rPaM.GetIndex(), bKeepEndingAttribs );
642cdf0e10cSrcweir 
643cdf0e10cSrcweir 	maTextNodes.Insert( pNew, rPaM.GetPara()+1 );
644cdf0e10cSrcweir 
645cdf0e10cSrcweir 	TextPaM aPaM( rPaM.GetPara()+1, 0 );
646cdf0e10cSrcweir 	return aPaM;
647cdf0e10cSrcweir }
648cdf0e10cSrcweir 
649cdf0e10cSrcweir TextPaM TextDoc::ConnectParagraphs( TextNode* pLeft, TextNode* pRight )
650cdf0e10cSrcweir {
651cdf0e10cSrcweir 	sal_uInt16 nPrevLen = pLeft->GetText().Len();
652cdf0e10cSrcweir 	pLeft->Append( *pRight );
653cdf0e10cSrcweir 
654cdf0e10cSrcweir 	// der rechte verschwindet.
655cdf0e10cSrcweir 	sal_uLong nRight = maTextNodes.GetPos( pRight );
656cdf0e10cSrcweir 	maTextNodes.Remove( nRight );
657cdf0e10cSrcweir 	delete pRight;
658cdf0e10cSrcweir 
659cdf0e10cSrcweir 	sal_uLong nLeft = maTextNodes.GetPos( pLeft );
660cdf0e10cSrcweir 	TextPaM aPaM( nLeft, nPrevLen );
661cdf0e10cSrcweir 	return aPaM;
662cdf0e10cSrcweir }
663cdf0e10cSrcweir 
664cdf0e10cSrcweir TextPaM TextDoc::RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars )
665cdf0e10cSrcweir {
666cdf0e10cSrcweir 	TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
667cdf0e10cSrcweir 	pNode->RemoveText( rPaM.GetIndex(), nChars );
668cdf0e10cSrcweir 
669cdf0e10cSrcweir 	return rPaM;
670cdf0e10cSrcweir }
671cdf0e10cSrcweir 
672cdf0e10cSrcweir sal_Bool TextDoc::IsValidPaM( const TextPaM& rPaM )
673cdf0e10cSrcweir {
674cdf0e10cSrcweir 	if ( rPaM.GetPara() >= maTextNodes.Count() )
675cdf0e10cSrcweir 	{
676cdf0e10cSrcweir 		DBG_ERROR( "PaM: Para out of range" );
677cdf0e10cSrcweir 		return sal_False;
678cdf0e10cSrcweir 	}
679cdf0e10cSrcweir 	TextNode * pNode = maTextNodes.GetObject( rPaM.GetPara() );
680cdf0e10cSrcweir 	if ( rPaM.GetIndex() > pNode->GetText().Len() )
681cdf0e10cSrcweir 	{
682cdf0e10cSrcweir 		DBG_ERROR( "PaM: Index out of range" );
683cdf0e10cSrcweir 		return sal_False;
684cdf0e10cSrcweir 	}
685cdf0e10cSrcweir 	return sal_True;
686cdf0e10cSrcweir }
687cdf0e10cSrcweir 
688cdf0e10cSrcweir /*
689cdf0e10cSrcweir 
690cdf0e10cSrcweir void TextDoc::InsertAttribInSelection( TextNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem )
691cdf0e10cSrcweir {
692cdf0e10cSrcweir 	DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
693cdf0e10cSrcweir 	DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
694cdf0e10cSrcweir 
695cdf0e10cSrcweir 	// fuer Optimierung:
696cdf0e10cSrcweir 	// dieses endet am Anfang der Selektion => kann erweitert werden
697cdf0e10cSrcweir 	TextCharAttrib* pEndingAttrib = 0;
698cdf0e10cSrcweir 	// dieses startet am Ende der Selektion => kann erweitert werden
699cdf0e10cSrcweir 	TextCharAttrib* pStartingAttrib = 0;
700cdf0e10cSrcweir 
701cdf0e10cSrcweir 	DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
702cdf0e10cSrcweir 
703cdf0e10cSrcweir 	RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
704cdf0e10cSrcweir 
705cdf0e10cSrcweir 	if ( pStartingAttrib && pEndingAttrib &&
706cdf0e10cSrcweir 		 ( *(pStartingAttrib->GetItem()) == rPoolItem ) &&
707cdf0e10cSrcweir 		 ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
708cdf0e10cSrcweir 	{
709cdf0e10cSrcweir 		// wird ein groesses Attribut.
710cdf0e10cSrcweir 		pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
711cdf0e10cSrcweir 		pCurPool->Remove( *(pStartingAttrib->GetItem()) );
712cdf0e10cSrcweir 		pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) );
713cdf0e10cSrcweir 		delete pStartingAttrib;
714cdf0e10cSrcweir 	}
715cdf0e10cSrcweir 	else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
716cdf0e10cSrcweir 		pStartingAttrib->GetStart() = nStart;
717cdf0e10cSrcweir 	else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
718cdf0e10cSrcweir 		pEndingAttrib->GetEnd() = nEnd;
719cdf0e10cSrcweir 	else
720cdf0e10cSrcweir 		InsertAttrib( rPoolItem, pNode, nStart, nEnd );
721cdf0e10cSrcweir 
722cdf0e10cSrcweir 	if ( pStartingAttrib )
723cdf0e10cSrcweir 		pNode->GetCharAttribs().ResortAttribs();
724cdf0e10cSrcweir }
725cdf0e10cSrcweir 
726cdf0e10cSrcweir sal_Bool TextDoc::RemoveAttribs( TextNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, sal_uInt16 nWhich )
727cdf0e10cSrcweir {
728cdf0e10cSrcweir 	TextCharAttrib* pStarting;
729cdf0e10cSrcweir 	TextCharAttrib* pEnding;
730cdf0e10cSrcweir 	return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich );
731cdf0e10cSrcweir }
732cdf0e10cSrcweir 
733cdf0e10cSrcweir sal_Bool TextDoc::RemoveAttribs( TextNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, TextCharAttrib*& rpStarting, TextCharAttrib*& rpEnding, sal_uInt16 nWhich )
734cdf0e10cSrcweir {
735cdf0e10cSrcweir 	DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
736cdf0e10cSrcweir 	DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
737cdf0e10cSrcweir 
738cdf0e10cSrcweir 	// dieses endet am Anfang der Selektion => kann erweitert werden
739cdf0e10cSrcweir 	rpEnding = 0;
740cdf0e10cSrcweir 	// dieses startet am Ende der Selektion => kann erweitert werden
741cdf0e10cSrcweir 	rpStarting = 0;
742cdf0e10cSrcweir 
743cdf0e10cSrcweir 	sal_Bool bChanged = sal_False;
744cdf0e10cSrcweir 
745cdf0e10cSrcweir 	DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
746cdf0e10cSrcweir 
747cdf0e10cSrcweir 	// ueber die Attribute iterieren...
748cdf0e10cSrcweir 	sal_uInt16 nAttr = 0;
749cdf0e10cSrcweir 	TextCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
750cdf0e10cSrcweir 	while ( pAttr )
751cdf0e10cSrcweir 	{
752cdf0e10cSrcweir 		sal_Bool bRemoveAttrib = sal_False;
753cdf0e10cSrcweir 		if ( !nWhich || ( pAttr->Which() == nWhich ) )
754cdf0e10cSrcweir 		{
755cdf0e10cSrcweir 			// Attribut beginnt in Selection
756cdf0e10cSrcweir 			if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
757cdf0e10cSrcweir 			{
758cdf0e10cSrcweir 				bChanged = sal_True;
759cdf0e10cSrcweir 				if ( pAttr->GetEnd() > nEnd )
760cdf0e10cSrcweir 				{
761cdf0e10cSrcweir 					pAttr->GetStart() = nEnd;	// dann faengt es dahinter an
762cdf0e10cSrcweir 					rpStarting = pAttr;
763cdf0e10cSrcweir 					break;	// es kann kein weiteres Attrib hier liegen
764cdf0e10cSrcweir 				}
765cdf0e10cSrcweir 				else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
766cdf0e10cSrcweir 				{
767cdf0e10cSrcweir 					// Feature nur loeschen, wenn genau an der Stelle
768cdf0e10cSrcweir 					bRemoveAttrib = sal_True;
769cdf0e10cSrcweir 				}
770cdf0e10cSrcweir 			}
771cdf0e10cSrcweir 
772cdf0e10cSrcweir 			// Attribut endet in Selection
773cdf0e10cSrcweir 			else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
774cdf0e10cSrcweir 			{
775cdf0e10cSrcweir 				bChanged = sal_True;
776cdf0e10cSrcweir 				if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
777cdf0e10cSrcweir 				{
778cdf0e10cSrcweir 					pAttr->GetEnd() = nStart;	// dann hoert es hier auf
779cdf0e10cSrcweir 					rpEnding = pAttr;
780cdf0e10cSrcweir 				}
781cdf0e10cSrcweir 				else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
782cdf0e10cSrcweir 				{
783cdf0e10cSrcweir 					// Feature nur loeschen, wenn genau an der Stelle
784cdf0e10cSrcweir 					bRemoveAttrib = sal_True;
785cdf0e10cSrcweir 				}
786cdf0e10cSrcweir 			}
787cdf0e10cSrcweir 			// Attribut ueberlappt die Selektion
788cdf0e10cSrcweir 			else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
789cdf0e10cSrcweir 			{
790cdf0e10cSrcweir 				bChanged = sal_True;
791cdf0e10cSrcweir 				if ( pAttr->GetStart() == nStart )
792cdf0e10cSrcweir 				{
793cdf0e10cSrcweir 					pAttr->GetStart() = nEnd;
794cdf0e10cSrcweir 					rpStarting = pAttr;
795cdf0e10cSrcweir 					break;	// es kann weitere Attribute geben!
796cdf0e10cSrcweir 				}
797cdf0e10cSrcweir 				else if ( pAttr->GetEnd() == nEnd )
798cdf0e10cSrcweir 				{
799cdf0e10cSrcweir 					pAttr->GetEnd() = nStart;
800cdf0e10cSrcweir 					rpEnding = pAttr;
801cdf0e10cSrcweir 					break;	// es kann weitere Attribute geben!
802cdf0e10cSrcweir 				}
803cdf0e10cSrcweir 				else // Attribut muss gesplittet werden...
804cdf0e10cSrcweir 				{
805cdf0e10cSrcweir 					sal_uInt16 nOldEnd = pAttr->GetEnd();
806cdf0e10cSrcweir 					pAttr->GetEnd() = nStart;
807cdf0e10cSrcweir 					rpEnding = pAttr;
808cdf0e10cSrcweir //					sal_uLong nSavePos = pNode->GetCharAttribs().GetStartList().GetCurPos();
809cdf0e10cSrcweir 					InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
810cdf0e10cSrcweir //					pNode->GetCharAttribs().GetStartList().Seek( nSavePos );
811cdf0e10cSrcweir 					break;	// es kann weitere Attribute geben!
812cdf0e10cSrcweir 				}
813cdf0e10cSrcweir 			}
814cdf0e10cSrcweir 		}
815cdf0e10cSrcweir 		if ( bRemoveAttrib )
816cdf0e10cSrcweir 		{
817cdf0e10cSrcweir 			DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Loeschen und behalten des gleichen Attributs ?" );
818cdf0e10cSrcweir 			pNode->GetCharAttribs().GetAttribs().Remove(nAttr);
819cdf0e10cSrcweir 			pCurPool->Remove( *pAttr->GetItem() );
820cdf0e10cSrcweir 			delete pAttr;
821cdf0e10cSrcweir 			nAttr--;
822cdf0e10cSrcweir 		}
823cdf0e10cSrcweir 		nAttr++;
824cdf0e10cSrcweir 		pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
825cdf0e10cSrcweir 	}
826cdf0e10cSrcweir 	return bChanged;
827cdf0e10cSrcweir }
828cdf0e10cSrcweir 
829cdf0e10cSrcweir #pragma SEG_FUNCDEF(editdoc_3f)
830cdf0e10cSrcweir 
831cdf0e10cSrcweir void TextDoc::InsertAttrib( const SfxPoolItem& rPoolItem, TextNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd )
832cdf0e10cSrcweir {
833cdf0e10cSrcweir 	// Diese Methode prueft nicht mehr, ob ein entspr. Attribut
834cdf0e10cSrcweir 	// schon an der Stelle existiert!
835cdf0e10cSrcweir 
836cdf0e10cSrcweir 	// pruefen, ob neues Attrib oder einfach nur Ende eines Attribs...
837cdf0e10cSrcweir //	const SfxPoolItem& rDefItem = pNode->GetContentAttribs().GetItem( rPoolItem.Which() );
838cdf0e10cSrcweir //	sal_Bool bCreateAttrib = ( rDefItem != rPoolItem );
839cdf0e10cSrcweir 
840cdf0e10cSrcweir 	// Durch den Verlust der Exclude-Liste geht es nicht mehr, dass ich
841cdf0e10cSrcweir 	// kein neues Attribut benoetige und nur das alte nicht expandiere...
842cdf0e10cSrcweir //	if ( !bCreateAttrib )
843cdf0e10cSrcweir 	{
844cdf0e10cSrcweir 		// => Wenn schon Default-Item, dann wenigstens nur dann einstellen,
845cdf0e10cSrcweir 		// wenn davor wirklich ein entsprechendes Attribut.
846cdf0e10cSrcweir //		if ( pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart ) )
847cdf0e10cSrcweir //			bCreateAttrib = sal_True;
848cdf0e10cSrcweir 		// Aber kleiner Trost:
849cdf0e10cSrcweir 		// Die wenigsten schreiben, aendern das Attr, schreiben, und
850cdf0e10cSrcweir 		// stellen dann wieder das Default-Attr ein.
851cdf0e10cSrcweir 	}
852cdf0e10cSrcweir 
853cdf0e10cSrcweir 	// 22.9.95:
854cdf0e10cSrcweir 	// Die Uberlegung, einfach das andere Attribut nicht zu expandieren, war
855cdf0e10cSrcweir 	// sowieso falsch, da das DefAttr aus einer Vorlage kommen kann,
856cdf0e10cSrcweir 	// die irgendwann verschwindet!
857cdf0e10cSrcweir //	if ( bCreateAttrib )
858cdf0e10cSrcweir //	{
859cdf0e10cSrcweir 		TextCharAttrib* pAttrib = MakeCharAttrib( *pCurPool, rPoolItem, nStart, nEnd );
860cdf0e10cSrcweir 		DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" );
861cdf0e10cSrcweir 		pNode->GetCharAttribs().InsertAttrib( pAttrib );
862cdf0e10cSrcweir //	}
863cdf0e10cSrcweir //	else
864cdf0e10cSrcweir //	{
865cdf0e10cSrcweir //		TextCharAttrib* pTmpAttrib =
866cdf0e10cSrcweir //			pNode->GetCharAttribs().FindAnyAttrib( rPoolItem.Which() );
867cdf0e10cSrcweir //		if ( pTmpAttrib ) 	// sonst benoetige ich es sowieso nicht....
868cdf0e10cSrcweir //		{
869cdf0e10cSrcweir //			aExcludeList.Insert( pTmpAttrib->GetItem() );
870cdf0e10cSrcweir //		}
871cdf0e10cSrcweir //	}
872cdf0e10cSrcweir }
873cdf0e10cSrcweir 
874cdf0e10cSrcweir #pragma SEG_FUNCDEF(editdoc_40)
875cdf0e10cSrcweir 
876cdf0e10cSrcweir void TextDoc::InsertAttrib( TextNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem )
877cdf0e10cSrcweir {
878cdf0e10cSrcweir 	if ( nStart != nEnd )
879cdf0e10cSrcweir 	{
880cdf0e10cSrcweir 		InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
881cdf0e10cSrcweir 	}
882cdf0e10cSrcweir 	else
883cdf0e10cSrcweir 	{
884cdf0e10cSrcweir 		// Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle:
885cdf0e10cSrcweir 		TextCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart );
886cdf0e10cSrcweir 		if ( pAttr )
887cdf0e10cSrcweir 		{
888cdf0e10cSrcweir 			// Attribut entfernen....
889cdf0e10cSrcweir 			pNode->GetCharAttribs().GetAttribs().Remove(
890cdf0e10cSrcweir 				pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) );
891cdf0e10cSrcweir 		}
892cdf0e10cSrcweir 
893cdf0e10cSrcweir 		// pruefen, ob ein 'gleiches' Attribut an der Stelle liegt.
894cdf0e10cSrcweir 		pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart );
895cdf0e10cSrcweir 		if ( pAttr )
896cdf0e10cSrcweir 		{
897cdf0e10cSrcweir 			if ( pAttr->IsInside( nStart ) )	// splitten
898cdf0e10cSrcweir 			{
899cdf0e10cSrcweir 				// ???????????????????????????????
900cdf0e10cSrcweir 				// eigentlich noch pruefen, ob wirklich splittet, oder return !
901cdf0e10cSrcweir 				// ???????????????????????????????
902cdf0e10cSrcweir 				sal_uInt16 nOldEnd = pAttr->GetEnd();
903cdf0e10cSrcweir 				pAttr->GetEnd() = nStart;
904cdf0e10cSrcweir 				pAttr = MakeCharAttrib( *pCurPool, *(pAttr->GetItem()), nStart, nOldEnd );
905cdf0e10cSrcweir 				pNode->GetCharAttribs().InsertAttrib( pAttr );
906cdf0e10cSrcweir 			}
907cdf0e10cSrcweir 			else if ( pAttr->GetEnd() == nStart )
908cdf0e10cSrcweir 			{
909cdf0e10cSrcweir 				DBG_ASSERT( !pAttr->IsEmpty(), "Doch noch ein leeres Attribut?" );
910cdf0e10cSrcweir 				// pruefen, ob genau das gleiche Attribut
911cdf0e10cSrcweir 				if ( *(pAttr->GetItem()) == rPoolItem )
912cdf0e10cSrcweir 					return;
913cdf0e10cSrcweir 			}
914cdf0e10cSrcweir 		}
915cdf0e10cSrcweir 		InsertAttrib( rPoolItem, pNode, nStart, nStart );
916cdf0e10cSrcweir 	}
917cdf0e10cSrcweir }
918cdf0e10cSrcweir 
919cdf0e10cSrcweir #pragma SEG_FUNCDEF(editdoc_41)
920cdf0e10cSrcweir 
921cdf0e10cSrcweir void TextDoc::FindAttribs( TextNode* pNode, sal_uInt16 nStartPos, sal_uInt16 nEndPos, SfxItemSet& rCurSet )
922cdf0e10cSrcweir {
923cdf0e10cSrcweir 	DBG_ASSERT( pNode, "Wo soll ich suchen ?" );
924cdf0e10cSrcweir 	DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" );
925cdf0e10cSrcweir 
926cdf0e10cSrcweir 	sal_uInt16 nAttr = 0;
927cdf0e10cSrcweir 	TextCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
928cdf0e10cSrcweir 	// keine Selection...
929cdf0e10cSrcweir 	if ( nStartPos == nEndPos )
930cdf0e10cSrcweir 	{
931cdf0e10cSrcweir 		while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
932cdf0e10cSrcweir 		{
933cdf0e10cSrcweir 			const SfxPoolItem* pItem = 0;
934cdf0e10cSrcweir 			// Attribut liegt dadrueber...
935cdf0e10cSrcweir 			if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
936cdf0e10cSrcweir 				pItem = pAttr->GetItem();
937cdf0e10cSrcweir 			// Attribut endet hier, ist nicht leer
938cdf0e10cSrcweir 			else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
939cdf0e10cSrcweir 			{
940cdf0e10cSrcweir 				if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) )
941cdf0e10cSrcweir 					pItem = pAttr->GetItem();
942cdf0e10cSrcweir 			}
943cdf0e10cSrcweir 			// Attribut endet hier, ist leer
944cdf0e10cSrcweir 			else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
945cdf0e10cSrcweir 			{
946cdf0e10cSrcweir //				if ( aExcludeList.FindAttrib( pAttr->GetItem()->Which() ) )
947cdf0e10cSrcweir 					pItem = pAttr->GetItem();
948cdf0e10cSrcweir //				else if ( pNode->Len() == 0 )	// Sonderfall
949cdf0e10cSrcweir //					pItem = pAttr->GetItem();
950cdf0e10cSrcweir 			}
951cdf0e10cSrcweir 			// Attribut beginnt hier
952cdf0e10cSrcweir 			else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
953cdf0e10cSrcweir 			{
954cdf0e10cSrcweir 				if ( nStartPos == 0 ) 	// Sonderfall
955cdf0e10cSrcweir 					pItem = pAttr->GetItem();
956cdf0e10cSrcweir 			}
957cdf0e10cSrcweir 
958cdf0e10cSrcweir 			if ( pItem )
959cdf0e10cSrcweir 			{
960cdf0e10cSrcweir 				sal_uInt16 nWhich = pItem->Which();
961cdf0e10cSrcweir 				if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
962cdf0e10cSrcweir 				{
963cdf0e10cSrcweir 					rCurSet.Put( *pItem );
964cdf0e10cSrcweir 				}
965cdf0e10cSrcweir 				else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
966cdf0e10cSrcweir 				{
967cdf0e10cSrcweir 					const SfxPoolItem& rItem = rCurSet.Get( nWhich );
968cdf0e10cSrcweir 					if ( rItem != *pItem )
969cdf0e10cSrcweir 					{
970cdf0e10cSrcweir 						rCurSet.InvalidateItem( nWhich );
971cdf0e10cSrcweir 					}
972cdf0e10cSrcweir 				}
973cdf0e10cSrcweir 			}
974cdf0e10cSrcweir 			nAttr++;
975cdf0e10cSrcweir 			pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
976cdf0e10cSrcweir 		}
977cdf0e10cSrcweir 	}
978cdf0e10cSrcweir 	else	// Selektion
979cdf0e10cSrcweir 	{
980cdf0e10cSrcweir 		while ( pAttr && ( pAttr->GetStart() < nEndPos) )
981cdf0e10cSrcweir 		{
982cdf0e10cSrcweir 			const SfxPoolItem* pItem = 0;
983cdf0e10cSrcweir 			// Attribut liegt dadrueber...
984cdf0e10cSrcweir 			if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
985cdf0e10cSrcweir 				pItem = pAttr->GetItem();
986cdf0e10cSrcweir 			// Attribut startet mitten drin...
987cdf0e10cSrcweir 			else if ( pAttr->GetStart() >= nStartPos )
988cdf0e10cSrcweir 			{
989cdf0e10cSrcweir 				// !!! pItem = pAttr->GetItem();
990cdf0e10cSrcweir 				// einfach nur pItem reicht nicht, da ich z.B. bei Shadow
991cdf0e10cSrcweir 				// niemals ein ungleiches Item finden wuerde, da ein solche
992cdf0e10cSrcweir 				// seine Anwesenheit durch Abwesenheit repraesentiert!
993cdf0e10cSrcweir 				// if ( ... )
994cdf0e10cSrcweir 				// Es muesste geprueft werden, on genau das gleiche Attribut
995cdf0e10cSrcweir 				// an der Bruchstelle aufsetzt, was recht aufwendig ist.
996cdf0e10cSrcweir 				// Da ich beim Einfuegen von Attributen aber etwas optimiere
997cdf0e10cSrcweir 				// tritt der Fall nicht so schnell auf...
998cdf0e10cSrcweir 				// Also aus Geschwindigkeitsgruenden:
999cdf0e10cSrcweir 				rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
1000cdf0e10cSrcweir 
1001cdf0e10cSrcweir 			}
1002cdf0e10cSrcweir 			// Attribut endet mitten drin...
1003cdf0e10cSrcweir 			else if ( pAttr->GetEnd() > nStartPos )
1004cdf0e10cSrcweir 			{
1005cdf0e10cSrcweir 				// pItem = pAttr->GetItem();
1006cdf0e10cSrcweir 				// s.o.
1007cdf0e10cSrcweir 
1008cdf0e10cSrcweir 				// -----------------31.05.95 16:01-------------------
1009cdf0e10cSrcweir 				//  Ist falsch, wenn das gleiche Attribut sofort wieder
1010cdf0e10cSrcweir 				//  eingestellt wird!
1011cdf0e10cSrcweir 				//  => Sollte am besten nicht vorkommen, also gleich beim
1012cdf0e10cSrcweir 				//  	Setzen von Attributen richtig machen!
1013cdf0e10cSrcweir 				// --------------------------------------------------
1014cdf0e10cSrcweir 				rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
1015cdf0e10cSrcweir 			}
1016cdf0e10cSrcweir 
1017cdf0e10cSrcweir 			if ( pItem )
1018cdf0e10cSrcweir 			{
1019cdf0e10cSrcweir 				sal_uInt16 nWhich = pItem->Which();
1020cdf0e10cSrcweir 				if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
1021cdf0e10cSrcweir 				{
1022cdf0e10cSrcweir 					rCurSet.Put( *pItem );
1023cdf0e10cSrcweir 				}
1024cdf0e10cSrcweir 				else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
1025cdf0e10cSrcweir 				{
1026cdf0e10cSrcweir 					const SfxPoolItem& rItem = rCurSet.Get( nWhich );
1027cdf0e10cSrcweir 					if ( rItem != *pItem )
1028cdf0e10cSrcweir 					{
1029cdf0e10cSrcweir 						rCurSet.InvalidateItem( nWhich );
1030cdf0e10cSrcweir 					}
1031cdf0e10cSrcweir 				}
1032cdf0e10cSrcweir 			}
1033cdf0e10cSrcweir 			nAttr++;
1034cdf0e10cSrcweir 			pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1035cdf0e10cSrcweir 		}
1036cdf0e10cSrcweir 	}
1037cdf0e10cSrcweir }
1038cdf0e10cSrcweir 
1039cdf0e10cSrcweir 
1040cdf0e10cSrcweir */
1041cdf0e10cSrcweir 
1042cdf0e10cSrcweir 
1043