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