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