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