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