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