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 31*cdf0e10cSrcweir 32*cdf0e10cSrcweir #include <tools/stream.hxx> 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir #include <svtools/texteng.hxx> 35*cdf0e10cSrcweir #include <svtools/textview.hxx> 36*cdf0e10cSrcweir #include <textdoc.hxx> 37*cdf0e10cSrcweir #include <textdat2.hxx> 38*cdf0e10cSrcweir #include <textundo.hxx> 39*cdf0e10cSrcweir #include <textund2.hxx> 40*cdf0e10cSrcweir #include <svl/ctloptions.hxx> 41*cdf0e10cSrcweir #include <vcl/window.hxx> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir #include <vcl/edit.hxx> 44*cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 45*cdf0e10cSrcweir #include <com/sun/star/beans/PropertyValues.hpp> 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir #ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_ 48*cdf0e10cSrcweir #include <com/sun/star/i18n/XBreakIterator.hpp> 49*cdf0e10cSrcweir #endif 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir #ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_ 52*cdf0e10cSrcweir #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 53*cdf0e10cSrcweir #endif 54*cdf0e10cSrcweir 55*cdf0e10cSrcweir #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_ 56*cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hpp> 57*cdf0e10cSrcweir #endif 58*cdf0e10cSrcweir 59*cdf0e10cSrcweir #ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_ 60*cdf0e10cSrcweir #include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp> 61*cdf0e10cSrcweir #endif 62*cdf0e10cSrcweir #include <com/sun/star/i18n/InputSequenceCheckMode.hpp> 63*cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptType.hpp> 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir #include <comphelper/processfactory.hxx> 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir #include <unotools/localedatawrapper.hxx> 68*cdf0e10cSrcweir #include <vcl/unohelp.hxx> 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir #include <vcl/svapp.hxx> 71*cdf0e10cSrcweir #include <vcl/unohelp.hxx> 72*cdf0e10cSrcweir #include <vcl/metric.hxx> 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir #include <unicode/ubidi.h> 75*cdf0e10cSrcweir 76*cdf0e10cSrcweir using namespace ::com::sun::star; 77*cdf0e10cSrcweir using namespace ::com::sun::star::uno; 78*cdf0e10cSrcweir using namespace ::rtl; 79*cdf0e10cSrcweir 80*cdf0e10cSrcweir typedef TextView* TextViewPtr; 81*cdf0e10cSrcweir SV_DECL_PTRARR( TextViews, TextViewPtr, 0, 1 ) 82*cdf0e10cSrcweir // SV_IMPL_PTRARR( TextViews, TextViewPtr ); 83*cdf0e10cSrcweir 84*cdf0e10cSrcweir SV_DECL_VARARR_SORT( TESortedPositions, sal_uLong, 16, 8 ) 85*cdf0e10cSrcweir SV_IMPL_VARARR_SORT( TESortedPositions, sal_uLong ) 86*cdf0e10cSrcweir 87*cdf0e10cSrcweir #define RESDIFF 10 88*cdf0e10cSrcweir #define SCRLRANGE 20 // 1/20 der Breite/Hoehe scrollen, wenn im QueryDrop 89*cdf0e10cSrcweir 90*cdf0e10cSrcweir 91*cdf0e10cSrcweir // ------------------------------------------------------------------------- 92*cdf0e10cSrcweir // (-) class TextEngine 93*cdf0e10cSrcweir // ------------------------------------------------------------------------- 94*cdf0e10cSrcweir TextEngine::TextEngine() 95*cdf0e10cSrcweir { 96*cdf0e10cSrcweir mpDoc = 0; 97*cdf0e10cSrcweir mpTEParaPortions = 0; 98*cdf0e10cSrcweir 99*cdf0e10cSrcweir mpViews = new TextViews; 100*cdf0e10cSrcweir mpActiveView = NULL; 101*cdf0e10cSrcweir 102*cdf0e10cSrcweir mbIsFormatting = sal_False; 103*cdf0e10cSrcweir mbFormatted = sal_False; 104*cdf0e10cSrcweir mbUpdate = sal_True; 105*cdf0e10cSrcweir mbModified = sal_False; 106*cdf0e10cSrcweir mbUndoEnabled = sal_False; 107*cdf0e10cSrcweir mbIsInUndo = sal_False; 108*cdf0e10cSrcweir mbDowning = sal_False; 109*cdf0e10cSrcweir mbRightToLeft = sal_False; 110*cdf0e10cSrcweir mbHasMultiLineParas = sal_False; 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir meAlign = TXTALIGN_LEFT; 113*cdf0e10cSrcweir 114*cdf0e10cSrcweir mnMaxTextWidth = 0; 115*cdf0e10cSrcweir mnMaxTextLen = 0; 116*cdf0e10cSrcweir mnCurTextWidth = 0xFFFFFFFF; 117*cdf0e10cSrcweir mnCurTextHeight = 0; 118*cdf0e10cSrcweir 119*cdf0e10cSrcweir mpUndoManager = NULL; 120*cdf0e10cSrcweir mpIMEInfos = NULL; 121*cdf0e10cSrcweir mpLocaleDataWrapper = NULL; 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir mpIdleFormatter = new IdleFormatter; 124*cdf0e10cSrcweir mpIdleFormatter->SetTimeoutHdl( LINK( this, TextEngine, IdleFormatHdl ) ); 125*cdf0e10cSrcweir 126*cdf0e10cSrcweir mpRefDev = new VirtualDevice; 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir ImpInitLayoutMode( mpRefDev ); 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir ImpInitDoc(); 131*cdf0e10cSrcweir 132*cdf0e10cSrcweir maTextColor = COL_BLACK; 133*cdf0e10cSrcweir Font aFont; 134*cdf0e10cSrcweir aFont.SetTransparent( sal_False ); 135*cdf0e10cSrcweir Color aFillColor( aFont.GetFillColor() ); 136*cdf0e10cSrcweir aFillColor.SetTransparency( 0 ); 137*cdf0e10cSrcweir aFont.SetFillColor( aFillColor ); 138*cdf0e10cSrcweir SetFont( aFont ); 139*cdf0e10cSrcweir } 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir TextEngine::~TextEngine() 142*cdf0e10cSrcweir { 143*cdf0e10cSrcweir mbDowning = sal_True; 144*cdf0e10cSrcweir 145*cdf0e10cSrcweir delete mpIdleFormatter; 146*cdf0e10cSrcweir delete mpDoc; 147*cdf0e10cSrcweir delete mpTEParaPortions; 148*cdf0e10cSrcweir delete mpViews; // nur die Liste, nicht die Vies 149*cdf0e10cSrcweir delete mpRefDev; 150*cdf0e10cSrcweir delete mpUndoManager; 151*cdf0e10cSrcweir delete mpIMEInfos; 152*cdf0e10cSrcweir delete mpLocaleDataWrapper; 153*cdf0e10cSrcweir } 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir void TextEngine::InsertView( TextView* pTextView ) 156*cdf0e10cSrcweir { 157*cdf0e10cSrcweir mpViews->Insert( pTextView, mpViews->Count() ); 158*cdf0e10cSrcweir pTextView->SetSelection( TextSelection() ); 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir if ( !GetActiveView() ) 161*cdf0e10cSrcweir SetActiveView( pTextView ); 162*cdf0e10cSrcweir } 163*cdf0e10cSrcweir 164*cdf0e10cSrcweir void TextEngine::RemoveView( TextView* pTextView ) 165*cdf0e10cSrcweir { 166*cdf0e10cSrcweir sal_uInt16 nPos = mpViews->GetPos( pTextView ); 167*cdf0e10cSrcweir if( nPos != USHRT_MAX ) 168*cdf0e10cSrcweir { 169*cdf0e10cSrcweir pTextView->HideCursor(); 170*cdf0e10cSrcweir mpViews->Remove( nPos, 1 ); 171*cdf0e10cSrcweir if ( pTextView == GetActiveView() ) 172*cdf0e10cSrcweir SetActiveView( 0 ); 173*cdf0e10cSrcweir } 174*cdf0e10cSrcweir } 175*cdf0e10cSrcweir 176*cdf0e10cSrcweir sal_uInt16 TextEngine::GetViewCount() const 177*cdf0e10cSrcweir { 178*cdf0e10cSrcweir return mpViews->Count(); 179*cdf0e10cSrcweir } 180*cdf0e10cSrcweir 181*cdf0e10cSrcweir TextView* TextEngine::GetView( sal_uInt16 nView ) const 182*cdf0e10cSrcweir { 183*cdf0e10cSrcweir return mpViews->GetObject( nView ); 184*cdf0e10cSrcweir } 185*cdf0e10cSrcweir 186*cdf0e10cSrcweir TextView* TextEngine::GetActiveView() const 187*cdf0e10cSrcweir { 188*cdf0e10cSrcweir return mpActiveView; 189*cdf0e10cSrcweir } 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir void TextEngine::SetActiveView( TextView* pTextView ) 192*cdf0e10cSrcweir { 193*cdf0e10cSrcweir if ( pTextView != mpActiveView ) 194*cdf0e10cSrcweir { 195*cdf0e10cSrcweir if ( mpActiveView ) 196*cdf0e10cSrcweir mpActiveView->HideSelection(); 197*cdf0e10cSrcweir 198*cdf0e10cSrcweir mpActiveView = pTextView; 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir if ( mpActiveView ) 201*cdf0e10cSrcweir mpActiveView->ShowSelection(); 202*cdf0e10cSrcweir } 203*cdf0e10cSrcweir } 204*cdf0e10cSrcweir 205*cdf0e10cSrcweir void TextEngine::SetFont( const Font& rFont ) 206*cdf0e10cSrcweir { 207*cdf0e10cSrcweir if ( rFont != maFont ) 208*cdf0e10cSrcweir { 209*cdf0e10cSrcweir maFont = rFont; 210*cdf0e10cSrcweir // #i40221# As the font's color now defaults to transparent (since i35764) 211*cdf0e10cSrcweir // we have to choose a useful textcolor in this case. 212*cdf0e10cSrcweir // Otherwise maTextColor and maFont.GetColor() are both transparent.... 213*cdf0e10cSrcweir if( rFont.GetColor() == COL_TRANSPARENT ) 214*cdf0e10cSrcweir maTextColor = COL_BLACK; 215*cdf0e10cSrcweir else 216*cdf0e10cSrcweir maTextColor = rFont.GetColor(); 217*cdf0e10cSrcweir 218*cdf0e10cSrcweir // Wegen Selektion keinen Transparenten Font zulassen... 219*cdf0e10cSrcweir // (Sonst spaeter in ImplPaint den Hintergrund anders loeschen...) 220*cdf0e10cSrcweir maFont.SetTransparent( sal_False ); 221*cdf0e10cSrcweir // Tell VCL not to use the font color, use text color from OutputDevice 222*cdf0e10cSrcweir maFont.SetColor( COL_TRANSPARENT ); 223*cdf0e10cSrcweir Color aFillColor( maFont.GetFillColor() ); 224*cdf0e10cSrcweir aFillColor.SetTransparency( 0 ); 225*cdf0e10cSrcweir maFont.SetFillColor( aFillColor ); 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir maFont.SetAlign( ALIGN_TOP ); 228*cdf0e10cSrcweir mpRefDev->SetFont( maFont); 229*cdf0e10cSrcweir Size aTextSize; 230*cdf0e10cSrcweir aTextSize.Width() = mpRefDev->GetTextWidth( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( " " ) ) ); 231*cdf0e10cSrcweir aTextSize.Height() = mpRefDev->GetTextHeight(); 232*cdf0e10cSrcweir if ( !aTextSize.Width() ) 233*cdf0e10cSrcweir aTextSize.Width() = mpRefDev->GetTextWidth( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "XXXX" ) ) ); 234*cdf0e10cSrcweir 235*cdf0e10cSrcweir mnDefTab = (sal_uInt16)aTextSize.Width(); 236*cdf0e10cSrcweir if ( !mnDefTab ) 237*cdf0e10cSrcweir mnDefTab = 1; 238*cdf0e10cSrcweir mnCharHeight = (sal_uInt16)aTextSize.Height(); 239*cdf0e10cSrcweir /* 240*cdf0e10cSrcweir // #93746# Doesn't work with CJK HalfWidth/FullWidth 241*cdf0e10cSrcweir FontMetric aRealFont( mpRefDev->GetFontMetric() ); 242*cdf0e10cSrcweir if ( aRealFont.GetPitch() == PITCH_FIXED ) 243*cdf0e10cSrcweir { 244*cdf0e10cSrcweir String aX100; 245*cdf0e10cSrcweir aX100.Fill( 100, 'X' ); 246*cdf0e10cSrcweir mnFixCharWidth100 = (sal_uInt16)mpRefDev->GetTextWidth( aX100 ); 247*cdf0e10cSrcweir } 248*cdf0e10cSrcweir else 249*cdf0e10cSrcweir */ 250*cdf0e10cSrcweir mnFixCharWidth100 = 0; 251*cdf0e10cSrcweir 252*cdf0e10cSrcweir FormatFullDoc(); 253*cdf0e10cSrcweir UpdateViews(); 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir for ( sal_uInt16 nView = mpViews->Count(); nView; ) 256*cdf0e10cSrcweir { 257*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( --nView ); 258*cdf0e10cSrcweir pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) ); 259*cdf0e10cSrcweir } 260*cdf0e10cSrcweir } 261*cdf0e10cSrcweir } 262*cdf0e10cSrcweir 263*cdf0e10cSrcweir void TextEngine::SetDefTab( sal_uInt16 nDefTab ) 264*cdf0e10cSrcweir { 265*cdf0e10cSrcweir mnDefTab = nDefTab; 266*cdf0e10cSrcweir // evtl neu setzen? 267*cdf0e10cSrcweir } 268*cdf0e10cSrcweir 269*cdf0e10cSrcweir void TextEngine::SetMaxTextLen( sal_uLong nLen ) 270*cdf0e10cSrcweir { 271*cdf0e10cSrcweir mnMaxTextLen = nLen; 272*cdf0e10cSrcweir } 273*cdf0e10cSrcweir 274*cdf0e10cSrcweir void TextEngine::SetMaxTextWidth( sal_uLong nMaxWidth ) 275*cdf0e10cSrcweir { 276*cdf0e10cSrcweir if ( nMaxWidth != mnMaxTextWidth ) 277*cdf0e10cSrcweir { 278*cdf0e10cSrcweir mnMaxTextWidth = Min( nMaxWidth, (sal_uLong)0x7FFFFFFF ); 279*cdf0e10cSrcweir FormatFullDoc(); 280*cdf0e10cSrcweir UpdateViews(); 281*cdf0e10cSrcweir } 282*cdf0e10cSrcweir } 283*cdf0e10cSrcweir 284*cdf0e10cSrcweir static sal_Unicode static_aLFText[] = { '\n', 0 }; 285*cdf0e10cSrcweir static sal_Unicode static_aCRText[] = { '\r', 0 }; 286*cdf0e10cSrcweir static sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 }; 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir static inline const sal_Unicode* static_getLineEndText( LineEnd aLineEnd ) 289*cdf0e10cSrcweir { 290*cdf0e10cSrcweir const sal_Unicode* pRet = NULL; 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir switch( aLineEnd ) 293*cdf0e10cSrcweir { 294*cdf0e10cSrcweir case LINEEND_LF: pRet = static_aLFText;break; 295*cdf0e10cSrcweir case LINEEND_CR: pRet = static_aCRText;break; 296*cdf0e10cSrcweir case LINEEND_CRLF: pRet = static_aCRLFText;break; 297*cdf0e10cSrcweir } 298*cdf0e10cSrcweir return pRet; 299*cdf0e10cSrcweir } 300*cdf0e10cSrcweir 301*cdf0e10cSrcweir void TextEngine::ReplaceText(const TextSelection& rSel, const String& rText) 302*cdf0e10cSrcweir { 303*cdf0e10cSrcweir ImpInsertText( rSel, rText ); 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir 306*cdf0e10cSrcweir String TextEngine::GetText( LineEnd aSeparator ) const 307*cdf0e10cSrcweir { 308*cdf0e10cSrcweir return mpDoc->GetText( static_getLineEndText( aSeparator ) ); 309*cdf0e10cSrcweir } 310*cdf0e10cSrcweir 311*cdf0e10cSrcweir String TextEngine::GetTextLines( LineEnd aSeparator ) const 312*cdf0e10cSrcweir { 313*cdf0e10cSrcweir String aText; 314*cdf0e10cSrcweir sal_uLong nParas = mpTEParaPortions->Count(); 315*cdf0e10cSrcweir const sal_Unicode* pSep = static_getLineEndText( aSeparator ); 316*cdf0e10cSrcweir for ( sal_uLong nP = 0; nP < nParas; nP++ ) 317*cdf0e10cSrcweir { 318*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP ); 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir sal_uInt16 nLines = pTEParaPortion->GetLines().Count(); 321*cdf0e10cSrcweir for ( sal_uInt16 nL = 0; nL < nLines; nL++ ) 322*cdf0e10cSrcweir { 323*cdf0e10cSrcweir TextLine* pLine = pTEParaPortion->GetLines()[nL]; 324*cdf0e10cSrcweir aText += pTEParaPortion->GetNode()->GetText().Copy( pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); 325*cdf0e10cSrcweir if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) ) 326*cdf0e10cSrcweir aText += pSep; 327*cdf0e10cSrcweir } 328*cdf0e10cSrcweir } 329*cdf0e10cSrcweir return aText; 330*cdf0e10cSrcweir } 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir String TextEngine::GetText( sal_uLong nPara ) const 333*cdf0e10cSrcweir { 334*cdf0e10cSrcweir return mpDoc->GetText( nPara ); 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir sal_uLong TextEngine::GetTextLen( LineEnd aSeparator ) const 338*cdf0e10cSrcweir { 339*cdf0e10cSrcweir return mpDoc->GetTextLen( static_getLineEndText( aSeparator ) ); 340*cdf0e10cSrcweir } 341*cdf0e10cSrcweir 342*cdf0e10cSrcweir sal_uLong TextEngine::GetTextLen( const TextSelection& rSel, LineEnd aSeparator ) const 343*cdf0e10cSrcweir { 344*cdf0e10cSrcweir TextSelection aSel( rSel ); 345*cdf0e10cSrcweir aSel.Justify(); 346*cdf0e10cSrcweir ValidateSelection( aSel ); 347*cdf0e10cSrcweir return mpDoc->GetTextLen( static_getLineEndText( aSeparator ), &aSel ); 348*cdf0e10cSrcweir } 349*cdf0e10cSrcweir 350*cdf0e10cSrcweir sal_uInt16 TextEngine::GetTextLen( sal_uLong nPara ) const 351*cdf0e10cSrcweir { 352*cdf0e10cSrcweir return mpDoc->GetNodes().GetObject( nPara )->GetText().Len(); 353*cdf0e10cSrcweir } 354*cdf0e10cSrcweir 355*cdf0e10cSrcweir void TextEngine::SetUpdateMode( sal_Bool bUpdate ) 356*cdf0e10cSrcweir { 357*cdf0e10cSrcweir if ( bUpdate != mbUpdate ) 358*cdf0e10cSrcweir { 359*cdf0e10cSrcweir mbUpdate = bUpdate; 360*cdf0e10cSrcweir if ( mbUpdate ) 361*cdf0e10cSrcweir { 362*cdf0e10cSrcweir FormatAndUpdate( GetActiveView() ); 363*cdf0e10cSrcweir if ( GetActiveView() ) 364*cdf0e10cSrcweir GetActiveView()->ShowCursor(); 365*cdf0e10cSrcweir } 366*cdf0e10cSrcweir } 367*cdf0e10cSrcweir } 368*cdf0e10cSrcweir 369*cdf0e10cSrcweir sal_Bool TextEngine::DoesKeyMoveCursor( const KeyEvent& rKeyEvent ) 370*cdf0e10cSrcweir { 371*cdf0e10cSrcweir sal_Bool bDoesMove = sal_False; 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir switch ( rKeyEvent.GetKeyCode().GetCode() ) 374*cdf0e10cSrcweir { 375*cdf0e10cSrcweir case KEY_UP: 376*cdf0e10cSrcweir case KEY_DOWN: 377*cdf0e10cSrcweir case KEY_LEFT: 378*cdf0e10cSrcweir case KEY_RIGHT: 379*cdf0e10cSrcweir case KEY_HOME: 380*cdf0e10cSrcweir case KEY_END: 381*cdf0e10cSrcweir case KEY_PAGEUP: 382*cdf0e10cSrcweir case KEY_PAGEDOWN: 383*cdf0e10cSrcweir { 384*cdf0e10cSrcweir if ( !rKeyEvent.GetKeyCode().IsMod2() ) 385*cdf0e10cSrcweir bDoesMove = sal_True; 386*cdf0e10cSrcweir } 387*cdf0e10cSrcweir break; 388*cdf0e10cSrcweir } 389*cdf0e10cSrcweir return bDoesMove; 390*cdf0e10cSrcweir } 391*cdf0e10cSrcweir 392*cdf0e10cSrcweir sal_Bool TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent ) 393*cdf0e10cSrcweir { 394*cdf0e10cSrcweir sal_Bool bDoesChange = sal_False; 395*cdf0e10cSrcweir 396*cdf0e10cSrcweir KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); 397*cdf0e10cSrcweir if ( eFunc != KEYFUNC_DONTKNOW ) 398*cdf0e10cSrcweir { 399*cdf0e10cSrcweir switch ( eFunc ) 400*cdf0e10cSrcweir { 401*cdf0e10cSrcweir case KEYFUNC_UNDO: 402*cdf0e10cSrcweir case KEYFUNC_REDO: 403*cdf0e10cSrcweir case KEYFUNC_CUT: 404*cdf0e10cSrcweir case KEYFUNC_PASTE: bDoesChange = sal_True; 405*cdf0e10cSrcweir break; 406*cdf0e10cSrcweir default: // wird dann evtl. unten bearbeitet. 407*cdf0e10cSrcweir eFunc = KEYFUNC_DONTKNOW; 408*cdf0e10cSrcweir } 409*cdf0e10cSrcweir } 410*cdf0e10cSrcweir if ( eFunc == KEYFUNC_DONTKNOW ) 411*cdf0e10cSrcweir { 412*cdf0e10cSrcweir switch ( rKeyEvent.GetKeyCode().GetCode() ) 413*cdf0e10cSrcweir { 414*cdf0e10cSrcweir case KEY_DELETE: 415*cdf0e10cSrcweir case KEY_BACKSPACE: 416*cdf0e10cSrcweir { 417*cdf0e10cSrcweir if ( !rKeyEvent.GetKeyCode().IsMod2() ) 418*cdf0e10cSrcweir bDoesChange = sal_True; 419*cdf0e10cSrcweir } 420*cdf0e10cSrcweir break; 421*cdf0e10cSrcweir case KEY_RETURN: 422*cdf0e10cSrcweir case KEY_TAB: 423*cdf0e10cSrcweir { 424*cdf0e10cSrcweir if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) 425*cdf0e10cSrcweir bDoesChange = sal_True; 426*cdf0e10cSrcweir } 427*cdf0e10cSrcweir break; 428*cdf0e10cSrcweir default: 429*cdf0e10cSrcweir { 430*cdf0e10cSrcweir bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent ); 431*cdf0e10cSrcweir } 432*cdf0e10cSrcweir } 433*cdf0e10cSrcweir } 434*cdf0e10cSrcweir return bDoesChange; 435*cdf0e10cSrcweir } 436*cdf0e10cSrcweir 437*cdf0e10cSrcweir sal_Bool TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent ) 438*cdf0e10cSrcweir { 439*cdf0e10cSrcweir if( rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 && 440*cdf0e10cSrcweir KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#: 441*cdf0e10cSrcweir KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) ) // check for Ctrl and Alt separately 442*cdf0e10cSrcweir { 443*cdf0e10cSrcweir return sal_True; 444*cdf0e10cSrcweir } 445*cdf0e10cSrcweir return sal_False; 446*cdf0e10cSrcweir } 447*cdf0e10cSrcweir 448*cdf0e10cSrcweir void TextEngine::ImpInitDoc() 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir if ( mpDoc ) 451*cdf0e10cSrcweir mpDoc->Clear(); 452*cdf0e10cSrcweir else 453*cdf0e10cSrcweir mpDoc = new TextDoc; 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir delete mpTEParaPortions; 456*cdf0e10cSrcweir mpTEParaPortions = new TEParaPortions; 457*cdf0e10cSrcweir 458*cdf0e10cSrcweir TextNode* pNode = new TextNode( String() ); 459*cdf0e10cSrcweir mpDoc->GetNodes().Insert( pNode, 0 ); 460*cdf0e10cSrcweir 461*cdf0e10cSrcweir TEParaPortion* pIniPortion = new TEParaPortion( pNode ); 462*cdf0e10cSrcweir mpTEParaPortions->Insert( pIniPortion, (sal_uLong)0 ); 463*cdf0e10cSrcweir 464*cdf0e10cSrcweir mbFormatted = sal_False; 465*cdf0e10cSrcweir 466*cdf0e10cSrcweir ImpParagraphRemoved( TEXT_PARA_ALL ); 467*cdf0e10cSrcweir ImpParagraphInserted( 0 ); 468*cdf0e10cSrcweir } 469*cdf0e10cSrcweir 470*cdf0e10cSrcweir String TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const 471*cdf0e10cSrcweir { 472*cdf0e10cSrcweir String aText; 473*cdf0e10cSrcweir 474*cdf0e10cSrcweir if ( !rSel.HasRange() ) 475*cdf0e10cSrcweir return aText; 476*cdf0e10cSrcweir 477*cdf0e10cSrcweir TextSelection aSel( rSel ); 478*cdf0e10cSrcweir aSel.Justify(); 479*cdf0e10cSrcweir 480*cdf0e10cSrcweir sal_uLong nStartPara = aSel.GetStart().GetPara(); 481*cdf0e10cSrcweir sal_uLong nEndPara = aSel.GetEnd().GetPara(); 482*cdf0e10cSrcweir const sal_Unicode* pSep = static_getLineEndText( aSeparator ); 483*cdf0e10cSrcweir for ( sal_uLong nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; nNode++ ) 484*cdf0e10cSrcweir { 485*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); 486*cdf0e10cSrcweir 487*cdf0e10cSrcweir sal_uInt16 nStartPos = 0; 488*cdf0e10cSrcweir sal_uInt16 nEndPos = pNode->GetText().Len(); 489*cdf0e10cSrcweir if ( nNode == nStartPara ) 490*cdf0e10cSrcweir nStartPos = aSel.GetStart().GetIndex(); 491*cdf0e10cSrcweir if ( nNode == nEndPara ) // kann auch == nStart sein! 492*cdf0e10cSrcweir nEndPos = aSel.GetEnd().GetIndex(); 493*cdf0e10cSrcweir 494*cdf0e10cSrcweir aText += pNode->GetText().Copy( nStartPos, nEndPos-nStartPos ); 495*cdf0e10cSrcweir if ( nNode < nEndPara ) 496*cdf0e10cSrcweir aText += pSep; 497*cdf0e10cSrcweir } 498*cdf0e10cSrcweir return aText; 499*cdf0e10cSrcweir } 500*cdf0e10cSrcweir 501*cdf0e10cSrcweir void TextEngine::ImpRemoveText() 502*cdf0e10cSrcweir { 503*cdf0e10cSrcweir ImpInitDoc(); 504*cdf0e10cSrcweir 505*cdf0e10cSrcweir TextPaM aStartPaM( 0, 0 ); 506*cdf0e10cSrcweir TextSelection aEmptySel( aStartPaM, aStartPaM ); 507*cdf0e10cSrcweir for ( sal_uInt16 nView = 0; nView < mpViews->Count(); nView++ ) 508*cdf0e10cSrcweir { 509*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( nView ); 510*cdf0e10cSrcweir pView->ImpSetSelection( aEmptySel ); 511*cdf0e10cSrcweir } 512*cdf0e10cSrcweir ResetUndo(); 513*cdf0e10cSrcweir } 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir void TextEngine::SetText( const XubString& rText ) 516*cdf0e10cSrcweir { 517*cdf0e10cSrcweir ImpRemoveText(); 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir sal_Bool bUndoCurrentlyEnabled = IsUndoEnabled(); 520*cdf0e10cSrcweir // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden. 521*cdf0e10cSrcweir EnableUndo( sal_False ); 522*cdf0e10cSrcweir 523*cdf0e10cSrcweir TextPaM aStartPaM( 0, 0 ); 524*cdf0e10cSrcweir TextSelection aEmptySel( aStartPaM, aStartPaM ); 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir TextPaM aPaM = aStartPaM; 527*cdf0e10cSrcweir if ( rText.Len() ) 528*cdf0e10cSrcweir aPaM = ImpInsertText( aEmptySel, rText ); 529*cdf0e10cSrcweir 530*cdf0e10cSrcweir for ( sal_uInt16 nView = 0; nView < mpViews->Count(); nView++ ) 531*cdf0e10cSrcweir { 532*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( nView ); 533*cdf0e10cSrcweir pView->ImpSetSelection( aEmptySel ); 534*cdf0e10cSrcweir 535*cdf0e10cSrcweir // Wenn kein Text, dann auch Kein Format&Update 536*cdf0e10cSrcweir // => Der Text bleibt stehen. 537*cdf0e10cSrcweir if ( !rText.Len() && GetUpdateMode() ) 538*cdf0e10cSrcweir pView->Invalidate(); 539*cdf0e10cSrcweir } 540*cdf0e10cSrcweir 541*cdf0e10cSrcweir if( !rText.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht. 542*cdf0e10cSrcweir mnCurTextHeight = 0; 543*cdf0e10cSrcweir 544*cdf0e10cSrcweir FormatAndUpdate(); 545*cdf0e10cSrcweir 546*cdf0e10cSrcweir EnableUndo( bUndoCurrentlyEnabled ); 547*cdf0e10cSrcweir DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" ); 548*cdf0e10cSrcweir } 549*cdf0e10cSrcweir 550*cdf0e10cSrcweir 551*cdf0e10cSrcweir void TextEngine::CursorMoved( sal_uLong nNode ) 552*cdf0e10cSrcweir { 553*cdf0e10cSrcweir // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer! 554*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); 555*cdf0e10cSrcweir if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && pNode->GetText().Len() ) 556*cdf0e10cSrcweir pNode->GetCharAttribs().DeleteEmptyAttribs(); 557*cdf0e10cSrcweir } 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir void TextEngine::ImpRemoveChars( const TextPaM& rPaM, sal_uInt16 nChars, SfxUndoAction* ) 560*cdf0e10cSrcweir { 561*cdf0e10cSrcweir DBG_ASSERT( nChars, "ImpRemoveChars - 0 Chars?!" ); 562*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 563*cdf0e10cSrcweir { 564*cdf0e10cSrcweir // Attribute muessen hier vorm RemoveChars fuer UNDO gesichert werden! 565*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); 566*cdf0e10cSrcweir XubString aStr( pNode->GetText().Copy( rPaM.GetIndex(), nChars ) ); 567*cdf0e10cSrcweir 568*cdf0e10cSrcweir // Pruefen, ob Attribute geloescht oder geaendert werden: 569*cdf0e10cSrcweir sal_uInt16 nStart = rPaM.GetIndex(); 570*cdf0e10cSrcweir sal_uInt16 nEnd = nStart + nChars; 571*cdf0e10cSrcweir for ( sal_uInt16 nAttr = pNode->GetCharAttribs().Count(); nAttr; ) 572*cdf0e10cSrcweir { 573*cdf0e10cSrcweir TextCharAttrib* pAttr = pNode->GetCharAttribs().GetAttrib( --nAttr ); 574*cdf0e10cSrcweir if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) ) 575*cdf0e10cSrcweir { 576*cdf0e10cSrcweir // TextSelection aSel( rPaM ); 577*cdf0e10cSrcweir // aSel.GetEnd().GetIndex() += nChars; 578*cdf0e10cSrcweir // TextUndoSetAttribs* pAttrUndo = CreateAttribUndo( aSel ); 579*cdf0e10cSrcweir // InsertUndo( pAttrUndo ); 580*cdf0e10cSrcweir break; // for 581*cdf0e10cSrcweir } 582*cdf0e10cSrcweir } 583*cdf0e10cSrcweir // if ( pCurUndo && ( CreateTextPaM( pCurUndo->GetEPaM() ) == rPaM ) ) 584*cdf0e10cSrcweir // pCurUndo->GetStr() += aStr; 585*cdf0e10cSrcweir // else 586*cdf0e10cSrcweir InsertUndo( new TextUndoRemoveChars( this, rPaM, aStr ) ); 587*cdf0e10cSrcweir } 588*cdf0e10cSrcweir 589*cdf0e10cSrcweir mpDoc->RemoveChars( rPaM, nChars ); 590*cdf0e10cSrcweir ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars ); 591*cdf0e10cSrcweir } 592*cdf0e10cSrcweir 593*cdf0e10cSrcweir TextPaM TextEngine::ImpConnectParagraphs( sal_uLong nLeft, sal_uLong nRight ) 594*cdf0e10cSrcweir { 595*cdf0e10cSrcweir DBG_ASSERT( nLeft != nRight, "Den gleichen Absatz zusammenfuegen ?" ); 596*cdf0e10cSrcweir 597*cdf0e10cSrcweir TextNode* pLeft = mpDoc->GetNodes().GetObject( nLeft ); 598*cdf0e10cSrcweir TextNode* pRight = mpDoc->GetNodes().GetObject( nRight ); 599*cdf0e10cSrcweir 600*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 601*cdf0e10cSrcweir InsertUndo( new TextUndoConnectParas( this, nLeft, pLeft->GetText().Len() ) ); 602*cdf0e10cSrcweir 603*cdf0e10cSrcweir // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg. 604*cdf0e10cSrcweir TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft ); 605*cdf0e10cSrcweir TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight ); 606*cdf0e10cSrcweir DBG_ASSERT( pLeft && pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" ); 607*cdf0e10cSrcweir DBG_ASSERT( pRight && pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" ); 608*cdf0e10cSrcweir 609*cdf0e10cSrcweir TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight ); 610*cdf0e10cSrcweir ImpParagraphRemoved( nRight ); 611*cdf0e10cSrcweir 612*cdf0e10cSrcweir pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->GetText().Len() ); 613*cdf0e10cSrcweir 614*cdf0e10cSrcweir mpTEParaPortions->Remove( nRight ); 615*cdf0e10cSrcweir delete pRightPortion; 616*cdf0e10cSrcweir // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht. 617*cdf0e10cSrcweir 618*cdf0e10cSrcweir return aPaM; 619*cdf0e10cSrcweir } 620*cdf0e10cSrcweir 621*cdf0e10cSrcweir TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel ) 622*cdf0e10cSrcweir { 623*cdf0e10cSrcweir if ( !rSel.HasRange() ) 624*cdf0e10cSrcweir return rSel.GetStart(); 625*cdf0e10cSrcweir 626*cdf0e10cSrcweir TextSelection aSel( rSel ); 627*cdf0e10cSrcweir aSel.Justify(); 628*cdf0e10cSrcweir TextPaM aStartPaM( aSel.GetStart() ); 629*cdf0e10cSrcweir TextPaM aEndPaM( aSel.GetEnd() ); 630*cdf0e10cSrcweir 631*cdf0e10cSrcweir CursorMoved( aStartPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden... 632*cdf0e10cSrcweir CursorMoved( aEndPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden... 633*cdf0e10cSrcweir 634*cdf0e10cSrcweir DBG_ASSERT( mpDoc->IsValidPaM( aStartPaM ), "Index im Wald in ImpDeleteText" ); 635*cdf0e10cSrcweir DBG_ASSERT( mpDoc->IsValidPaM( aEndPaM ), "Index im Wald in ImpDeleteText" ); 636*cdf0e10cSrcweir 637*cdf0e10cSrcweir sal_uLong nStartNode = aStartPaM.GetPara(); 638*cdf0e10cSrcweir sal_uLong nEndNode = aEndPaM.GetPara(); 639*cdf0e10cSrcweir 640*cdf0e10cSrcweir // Alle Nodes dazwischen entfernen.... 641*cdf0e10cSrcweir for ( sal_uLong z = nStartNode+1; z < nEndNode; z++ ) 642*cdf0e10cSrcweir { 643*cdf0e10cSrcweir // Immer nStartNode+1, wegen Remove()! 644*cdf0e10cSrcweir ImpRemoveParagraph( nStartNode+1 ); 645*cdf0e10cSrcweir } 646*cdf0e10cSrcweir 647*cdf0e10cSrcweir if ( nStartNode != nEndNode ) 648*cdf0e10cSrcweir { 649*cdf0e10cSrcweir // Den Rest des StartNodes... 650*cdf0e10cSrcweir TextNode* pLeft = mpDoc->GetNodes().GetObject( nStartNode ); 651*cdf0e10cSrcweir sal_uInt16 nChars = pLeft->GetText().Len() - aStartPaM.GetIndex(); 652*cdf0e10cSrcweir if ( nChars ) 653*cdf0e10cSrcweir { 654*cdf0e10cSrcweir ImpRemoveChars( aStartPaM, nChars ); 655*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); 656*cdf0e10cSrcweir DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(3)" ); 657*cdf0e10cSrcweir pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), pLeft->GetText().Len() ); 658*cdf0e10cSrcweir } 659*cdf0e10cSrcweir 660*cdf0e10cSrcweir // Den Anfang des EndNodes.... 661*cdf0e10cSrcweir nEndNode = nStartNode+1; // Die anderen Absaetze wurden geloescht 662*cdf0e10cSrcweir nChars = aEndPaM.GetIndex(); 663*cdf0e10cSrcweir if ( nChars ) 664*cdf0e10cSrcweir { 665*cdf0e10cSrcweir aEndPaM.GetPara() = nEndNode; 666*cdf0e10cSrcweir aEndPaM.GetIndex() = 0; 667*cdf0e10cSrcweir ImpRemoveChars( aEndPaM, nChars ); 668*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode ); 669*cdf0e10cSrcweir DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(4)" ); 670*cdf0e10cSrcweir pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->GetText().Len() ); 671*cdf0e10cSrcweir } 672*cdf0e10cSrcweir 673*cdf0e10cSrcweir // Zusammenfuegen.... 674*cdf0e10cSrcweir aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode ); 675*cdf0e10cSrcweir } 676*cdf0e10cSrcweir else 677*cdf0e10cSrcweir { 678*cdf0e10cSrcweir sal_uInt16 nChars; 679*cdf0e10cSrcweir nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex(); 680*cdf0e10cSrcweir ImpRemoveChars( aStartPaM, nChars ); 681*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); 682*cdf0e10cSrcweir DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(5)" ); 683*cdf0e10cSrcweir pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); 684*cdf0e10cSrcweir } 685*cdf0e10cSrcweir 686*cdf0e10cSrcweir // UpdateSelections(); 687*cdf0e10cSrcweir TextModified(); 688*cdf0e10cSrcweir return aStartPaM; 689*cdf0e10cSrcweir } 690*cdf0e10cSrcweir 691*cdf0e10cSrcweir void TextEngine::ImpRemoveParagraph( sal_uLong nPara ) 692*cdf0e10cSrcweir { 693*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 694*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); 695*cdf0e10cSrcweir 696*cdf0e10cSrcweir // Der Node wird vom Undo verwaltet und ggf. zerstoert! 697*cdf0e10cSrcweir /* delete */ mpDoc->GetNodes().Remove( nPara ); 698*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 699*cdf0e10cSrcweir InsertUndo( new TextUndoDelPara( this, pNode, nPara ) ); 700*cdf0e10cSrcweir else 701*cdf0e10cSrcweir delete pNode; 702*cdf0e10cSrcweir 703*cdf0e10cSrcweir mpTEParaPortions->Remove( nPara ); 704*cdf0e10cSrcweir delete pPortion; 705*cdf0e10cSrcweir 706*cdf0e10cSrcweir ImpParagraphRemoved( nPara ); 707*cdf0e10cSrcweir } 708*cdf0e10cSrcweir 709*cdf0e10cSrcweir uno::Reference < i18n::XExtendedInputSequenceChecker > TextEngine::GetInputSequenceChecker() const 710*cdf0e10cSrcweir { 711*cdf0e10cSrcweir uno::Reference < i18n::XExtendedInputSequenceChecker > xISC; 712*cdf0e10cSrcweir // if ( !xISC.is() ) 713*cdf0e10cSrcweir { 714*cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 715*cdf0e10cSrcweir uno::Reference< uno::XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) ); 716*cdf0e10cSrcweir if ( xI.is() ) 717*cdf0e10cSrcweir { 718*cdf0e10cSrcweir Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XExtendedInputSequenceChecker >*)0) ); 719*cdf0e10cSrcweir x >>= xISC; 720*cdf0e10cSrcweir } 721*cdf0e10cSrcweir } 722*cdf0e10cSrcweir return xISC; 723*cdf0e10cSrcweir } 724*cdf0e10cSrcweir 725*cdf0e10cSrcweir sal_Bool TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const 726*cdf0e10cSrcweir { 727*cdf0e10cSrcweir uno::Reference< i18n::XBreakIterator > xBI = ((TextEngine *) this)->GetBreakIterator(); 728*cdf0e10cSrcweir SvtCTLOptions aCTLOptions; 729*cdf0e10cSrcweir 730*cdf0e10cSrcweir // get the index that really is first 731*cdf0e10cSrcweir sal_uInt16 nFirstPos = rCurSel.GetStart().GetIndex(); 732*cdf0e10cSrcweir sal_uInt16 nMaxPos = rCurSel.GetEnd().GetIndex(); 733*cdf0e10cSrcweir if (nMaxPos < nFirstPos) 734*cdf0e10cSrcweir nFirstPos = nMaxPos; 735*cdf0e10cSrcweir 736*cdf0e10cSrcweir sal_Bool bIsSequenceChecking = 737*cdf0e10cSrcweir aCTLOptions.IsCTLFontEnabled() && 738*cdf0e10cSrcweir aCTLOptions.IsCTLSequenceChecking() && 739*cdf0e10cSrcweir nFirstPos != 0 && /* first char needs not to be checked */ 740*cdf0e10cSrcweir xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rtl::OUString( c ), 0 ); 741*cdf0e10cSrcweir 742*cdf0e10cSrcweir return bIsSequenceChecking; 743*cdf0e10cSrcweir } 744*cdf0e10cSrcweir 745*cdf0e10cSrcweir TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, sal_Bool bOverwrite ) 746*cdf0e10cSrcweir { 747*cdf0e10cSrcweir return ImpInsertText( c, rCurSel, bOverwrite, sal_False ); 748*cdf0e10cSrcweir } 749*cdf0e10cSrcweir 750*cdf0e10cSrcweir TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, sal_Bool bOverwrite, sal_Bool bIsUserInput ) 751*cdf0e10cSrcweir { 752*cdf0e10cSrcweir DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" ); 753*cdf0e10cSrcweir DBG_ASSERT( c != '\r', "Zeilenumbruch bei InsertText ?" ); 754*cdf0e10cSrcweir 755*cdf0e10cSrcweir TextPaM aPaM( rCurSel.GetStart() ); 756*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 757*cdf0e10cSrcweir 758*cdf0e10cSrcweir if ( pNode->GetText().Len() < STRING_MAXLEN ) 759*cdf0e10cSrcweir { 760*cdf0e10cSrcweir sal_Bool bDoOverwrite = ( bOverwrite && 761*cdf0e10cSrcweir ( aPaM.GetIndex() < pNode->GetText().Len() ) ) ? sal_True : sal_False; 762*cdf0e10cSrcweir 763*cdf0e10cSrcweir sal_Bool bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); 764*cdf0e10cSrcweir 765*cdf0e10cSrcweir if ( bUndoAction ) 766*cdf0e10cSrcweir UndoActionStart(); 767*cdf0e10cSrcweir 768*cdf0e10cSrcweir if ( rCurSel.HasRange() ) 769*cdf0e10cSrcweir { 770*cdf0e10cSrcweir aPaM = ImpDeleteText( rCurSel ); 771*cdf0e10cSrcweir } 772*cdf0e10cSrcweir else if ( bDoOverwrite ) 773*cdf0e10cSrcweir { 774*cdf0e10cSrcweir // Wenn Selektion, dann kein Zeichen ueberschreiben 775*cdf0e10cSrcweir TextSelection aTmpSel( aPaM ); 776*cdf0e10cSrcweir aTmpSel.GetEnd().GetIndex()++; 777*cdf0e10cSrcweir ImpDeleteText( aTmpSel ); 778*cdf0e10cSrcweir } 779*cdf0e10cSrcweir 780*cdf0e10cSrcweir if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel )) 781*cdf0e10cSrcweir { 782*cdf0e10cSrcweir uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker(); 783*cdf0e10cSrcweir SvtCTLOptions aCTLOptions; 784*cdf0e10cSrcweir 785*cdf0e10cSrcweir if (xISC.is()) 786*cdf0e10cSrcweir { 787*cdf0e10cSrcweir xub_StrLen nTmpPos = aPaM.GetIndex(); 788*cdf0e10cSrcweir sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ? 789*cdf0e10cSrcweir i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; 790*cdf0e10cSrcweir 791*cdf0e10cSrcweir // the text that needs to be checked is only the one 792*cdf0e10cSrcweir // before the current cursor position 793*cdf0e10cSrcweir rtl::OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).Copy(0, nTmpPos) ); 794*cdf0e10cSrcweir rtl::OUString aNewText( aOldText ); 795*cdf0e10cSrcweir if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace()) 796*cdf0e10cSrcweir { 797*cdf0e10cSrcweir xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode ); 798*cdf0e10cSrcweir 799*cdf0e10cSrcweir // find position of first character that has changed 800*cdf0e10cSrcweir sal_Int32 nOldLen = aOldText.getLength(); 801*cdf0e10cSrcweir sal_Int32 nNewLen = aNewText.getLength(); 802*cdf0e10cSrcweir const sal_Unicode *pOldTxt = aOldText.getStr(); 803*cdf0e10cSrcweir const sal_Unicode *pNewTxt = aNewText.getStr(); 804*cdf0e10cSrcweir sal_Int32 nChgPos = 0; 805*cdf0e10cSrcweir while ( nChgPos < nOldLen && nChgPos < nNewLen && 806*cdf0e10cSrcweir pOldTxt[nChgPos] == pNewTxt[nChgPos] ) 807*cdf0e10cSrcweir ++nChgPos; 808*cdf0e10cSrcweir 809*cdf0e10cSrcweir xub_StrLen nChgLen = static_cast< xub_StrLen >(nNewLen - nChgPos); 810*cdf0e10cSrcweir String aChgText( aNewText.copy( nChgPos ), nChgLen ); 811*cdf0e10cSrcweir 812*cdf0e10cSrcweir // select text from first pos to be changed to current pos 813*cdf0e10cSrcweir TextSelection aSel( TextPaM( aPaM.GetPara(), (sal_uInt16) nChgPos ), aPaM ); 814*cdf0e10cSrcweir 815*cdf0e10cSrcweir if (aChgText.Len()) 816*cdf0e10cSrcweir // ImpInsertText implicitly handles undo... 817*cdf0e10cSrcweir return ImpInsertText( aSel, aChgText ); 818*cdf0e10cSrcweir else 819*cdf0e10cSrcweir return aPaM; 820*cdf0e10cSrcweir } 821*cdf0e10cSrcweir else 822*cdf0e10cSrcweir { 823*cdf0e10cSrcweir // should the character be ignored (i.e. not get inserted) ? 824*cdf0e10cSrcweir if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) 825*cdf0e10cSrcweir return aPaM; // nothing to be done -> no need for undo 826*cdf0e10cSrcweir } 827*cdf0e10cSrcweir } 828*cdf0e10cSrcweir 829*cdf0e10cSrcweir // at this point now we will insert the character 'normally' some lines below... 830*cdf0e10cSrcweir } 831*cdf0e10cSrcweir 832*cdf0e10cSrcweir 833*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 834*cdf0e10cSrcweir { 835*cdf0e10cSrcweir TextUndoInsertChars* pNewUndo = new TextUndoInsertChars( this, aPaM, c ); 836*cdf0e10cSrcweir sal_Bool bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? sal_True : sal_False; 837*cdf0e10cSrcweir InsertUndo( pNewUndo, bTryMerge ); 838*cdf0e10cSrcweir } 839*cdf0e10cSrcweir 840*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); 841*cdf0e10cSrcweir pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); 842*cdf0e10cSrcweir if ( c == '\t' ) 843*cdf0e10cSrcweir pPortion->SetNotSimpleInvalid(); 844*cdf0e10cSrcweir aPaM = mpDoc->InsertText( aPaM, c ); 845*cdf0e10cSrcweir ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 ); 846*cdf0e10cSrcweir 847*cdf0e10cSrcweir TextModified(); 848*cdf0e10cSrcweir 849*cdf0e10cSrcweir if ( bUndoAction ) 850*cdf0e10cSrcweir UndoActionEnd(); 851*cdf0e10cSrcweir } 852*cdf0e10cSrcweir 853*cdf0e10cSrcweir return aPaM; 854*cdf0e10cSrcweir } 855*cdf0e10cSrcweir 856*cdf0e10cSrcweir 857*cdf0e10cSrcweir TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString& rStr ) 858*cdf0e10cSrcweir { 859*cdf0e10cSrcweir UndoActionStart(); 860*cdf0e10cSrcweir 861*cdf0e10cSrcweir TextPaM aPaM; 862*cdf0e10cSrcweir 863*cdf0e10cSrcweir if ( rCurSel.HasRange() ) 864*cdf0e10cSrcweir aPaM = ImpDeleteText( rCurSel ); 865*cdf0e10cSrcweir else 866*cdf0e10cSrcweir aPaM = rCurSel.GetEnd(); 867*cdf0e10cSrcweir 868*cdf0e10cSrcweir XubString aText( rStr ); 869*cdf0e10cSrcweir aText.ConvertLineEnd( LINEEND_LF ); 870*cdf0e10cSrcweir 871*cdf0e10cSrcweir sal_uInt16 nStart = 0; 872*cdf0e10cSrcweir while ( nStart < aText.Len() ) 873*cdf0e10cSrcweir { 874*cdf0e10cSrcweir sal_uInt16 nEnd = aText.Search( LINE_SEP, nStart ); 875*cdf0e10cSrcweir if ( nEnd == STRING_NOTFOUND ) 876*cdf0e10cSrcweir nEnd = aText.Len(); // nicht dereferenzieren! 877*cdf0e10cSrcweir 878*cdf0e10cSrcweir // Start == End => Leerzeile 879*cdf0e10cSrcweir if ( nEnd > nStart ) 880*cdf0e10cSrcweir { 881*cdf0e10cSrcweir sal_uLong nL = aPaM.GetIndex(); 882*cdf0e10cSrcweir nL += ( nEnd-nStart ); 883*cdf0e10cSrcweir if ( nL > STRING_MAXLEN ) 884*cdf0e10cSrcweir { 885*cdf0e10cSrcweir sal_uInt16 nDiff = (sal_uInt16) (nL-STRING_MAXLEN); 886*cdf0e10cSrcweir nEnd = nEnd - nDiff; 887*cdf0e10cSrcweir } 888*cdf0e10cSrcweir 889*cdf0e10cSrcweir XubString aLine( aText, nStart, nEnd-nStart ); 890*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 891*cdf0e10cSrcweir InsertUndo( new TextUndoInsertChars( this, aPaM, aLine ) ); 892*cdf0e10cSrcweir 893*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); 894*cdf0e10cSrcweir pPortion->MarkInvalid( aPaM.GetIndex(), aLine.Len() ); 895*cdf0e10cSrcweir if ( aLine.Search( '\t' ) != STRING_NOTFOUND ) 896*cdf0e10cSrcweir pPortion->SetNotSimpleInvalid(); 897*cdf0e10cSrcweir 898*cdf0e10cSrcweir aPaM = mpDoc->InsertText( aPaM, aLine ); 899*cdf0e10cSrcweir ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.Len(), aLine.Len() ); 900*cdf0e10cSrcweir 901*cdf0e10cSrcweir } 902*cdf0e10cSrcweir if ( nEnd < aText.Len() ) 903*cdf0e10cSrcweir aPaM = ImpInsertParaBreak( aPaM ); 904*cdf0e10cSrcweir 905*cdf0e10cSrcweir nStart = nEnd+1; 906*cdf0e10cSrcweir 907*cdf0e10cSrcweir if ( nStart < nEnd ) // #108611# overflow 908*cdf0e10cSrcweir break; 909*cdf0e10cSrcweir } 910*cdf0e10cSrcweir 911*cdf0e10cSrcweir UndoActionEnd(); 912*cdf0e10cSrcweir 913*cdf0e10cSrcweir TextModified(); 914*cdf0e10cSrcweir return aPaM; 915*cdf0e10cSrcweir } 916*cdf0e10cSrcweir 917*cdf0e10cSrcweir TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel, sal_Bool bKeepEndingAttribs ) 918*cdf0e10cSrcweir { 919*cdf0e10cSrcweir TextPaM aPaM; 920*cdf0e10cSrcweir if ( rCurSel.HasRange() ) 921*cdf0e10cSrcweir aPaM = ImpDeleteText( rCurSel ); 922*cdf0e10cSrcweir else 923*cdf0e10cSrcweir aPaM = rCurSel.GetEnd(); 924*cdf0e10cSrcweir 925*cdf0e10cSrcweir return ImpInsertParaBreak( aPaM, bKeepEndingAttribs ); 926*cdf0e10cSrcweir } 927*cdf0e10cSrcweir 928*cdf0e10cSrcweir TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ) 929*cdf0e10cSrcweir { 930*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 931*cdf0e10cSrcweir InsertUndo( new TextUndoSplitPara( this, rPaM.GetPara(), rPaM.GetIndex() ) ); 932*cdf0e10cSrcweir 933*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); 934*cdf0e10cSrcweir sal_Bool bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().Len(); 935*cdf0e10cSrcweir 936*cdf0e10cSrcweir TextPaM aPaM( mpDoc->InsertParaBreak( rPaM, bKeepEndingAttribs ) ); 937*cdf0e10cSrcweir 938*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); 939*cdf0e10cSrcweir DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" ); 940*cdf0e10cSrcweir pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); 941*cdf0e10cSrcweir 942*cdf0e10cSrcweir TextNode* pNewNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() ); 943*cdf0e10cSrcweir TEParaPortion* pNewPortion = new TEParaPortion( pNewNode ); 944*cdf0e10cSrcweir mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() ); 945*cdf0e10cSrcweir ImpParagraphInserted( aPaM.GetPara() ); 946*cdf0e10cSrcweir 947*cdf0e10cSrcweir CursorMoved( rPaM.GetPara() ); // falls leeres Attribut entstanden. 948*cdf0e10cSrcweir TextModified(); 949*cdf0e10cSrcweir 950*cdf0e10cSrcweir if ( bFirstParaContentChanged ) 951*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, rPaM.GetPara() ) ); 952*cdf0e10cSrcweir 953*cdf0e10cSrcweir return aPaM; 954*cdf0e10cSrcweir } 955*cdf0e10cSrcweir 956*cdf0e10cSrcweir Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, sal_Bool bSpecial ) 957*cdf0e10cSrcweir { 958*cdf0e10cSrcweir DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: PaMtoEditCursor" ); 959*cdf0e10cSrcweir 960*cdf0e10cSrcweir Rectangle aEditCursor; 961*cdf0e10cSrcweir long nY = 0; 962*cdf0e10cSrcweir 963*cdf0e10cSrcweir if ( !mbHasMultiLineParas ) 964*cdf0e10cSrcweir { 965*cdf0e10cSrcweir nY = rPaM.GetPara() * mnCharHeight; 966*cdf0e10cSrcweir } 967*cdf0e10cSrcweir else 968*cdf0e10cSrcweir { 969*cdf0e10cSrcweir for ( sal_uLong nPortion = 0; nPortion < rPaM.GetPara(); nPortion++ ) 970*cdf0e10cSrcweir { 971*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion); 972*cdf0e10cSrcweir nY += pPortion->GetLines().Count() * mnCharHeight; 973*cdf0e10cSrcweir } 974*cdf0e10cSrcweir } 975*cdf0e10cSrcweir 976*cdf0e10cSrcweir aEditCursor = GetEditCursor( rPaM, bSpecial ); 977*cdf0e10cSrcweir aEditCursor.Top() += nY; 978*cdf0e10cSrcweir aEditCursor.Bottom() += nY; 979*cdf0e10cSrcweir return aEditCursor; 980*cdf0e10cSrcweir } 981*cdf0e10cSrcweir 982*cdf0e10cSrcweir Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, sal_Bool bSpecial, sal_Bool bPreferPortionStart ) 983*cdf0e10cSrcweir { 984*cdf0e10cSrcweir if ( !IsFormatted() && !IsFormatting() ) 985*cdf0e10cSrcweir FormatAndUpdate(); 986*cdf0e10cSrcweir 987*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); 988*cdf0e10cSrcweir //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); 989*cdf0e10cSrcweir 990*cdf0e10cSrcweir /* 991*cdf0e10cSrcweir bSpecial: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile, 992*cdf0e10cSrcweir am Ende der Zeile bleiben, nicht am Anfang der naechsten. 993*cdf0e10cSrcweir Zweck: - END => wirklich hinter das letzte Zeichen 994*cdf0e10cSrcweir - Selektion.... 995*cdf0e10cSrcweir bSpecial: If behind the last character of a made up line, stay at the 996*cdf0e10cSrcweir end of the line, not at the start of the next line. 997*cdf0e10cSrcweir Purpose: - really END = > behind the last character 998*cdf0e10cSrcweir - to selection... 999*cdf0e10cSrcweir 1000*cdf0e10cSrcweir */ 1001*cdf0e10cSrcweir 1002*cdf0e10cSrcweir long nY = 0; 1003*cdf0e10cSrcweir sal_uInt16 nCurIndex = 0; 1004*cdf0e10cSrcweir TextLine* pLine = 0; 1005*cdf0e10cSrcweir for ( sal_uInt16 nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) 1006*cdf0e10cSrcweir { 1007*cdf0e10cSrcweir TextLine* pTmpLine = pPortion->GetLines().GetObject( nLine ); 1008*cdf0e10cSrcweir if ( ( pTmpLine->GetStart() == rPaM.GetIndex() ) || ( pTmpLine->IsIn( rPaM.GetIndex(), bSpecial ) ) ) 1009*cdf0e10cSrcweir { 1010*cdf0e10cSrcweir pLine = pTmpLine; 1011*cdf0e10cSrcweir break; 1012*cdf0e10cSrcweir } 1013*cdf0e10cSrcweir 1014*cdf0e10cSrcweir nCurIndex = nCurIndex + pTmpLine->GetLen(); 1015*cdf0e10cSrcweir nY += mnCharHeight; 1016*cdf0e10cSrcweir } 1017*cdf0e10cSrcweir if ( !pLine ) 1018*cdf0e10cSrcweir { 1019*cdf0e10cSrcweir // Cursor am Ende des Absatzes. 1020*cdf0e10cSrcweir DBG_ASSERT( rPaM.GetIndex() == nCurIndex, "Index voll daneben in GetEditCursor!" ); 1021*cdf0e10cSrcweir 1022*cdf0e10cSrcweir pLine = pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1 ); 1023*cdf0e10cSrcweir nY -= mnCharHeight; 1024*cdf0e10cSrcweir nCurIndex = nCurIndex - pLine->GetLen(); 1025*cdf0e10cSrcweir } 1026*cdf0e10cSrcweir 1027*cdf0e10cSrcweir Rectangle aEditCursor; 1028*cdf0e10cSrcweir 1029*cdf0e10cSrcweir aEditCursor.Top() = nY; 1030*cdf0e10cSrcweir nY += mnCharHeight; 1031*cdf0e10cSrcweir aEditCursor.Bottom() = nY-1; 1032*cdf0e10cSrcweir 1033*cdf0e10cSrcweir // innerhalb der Zeile suchen.... 1034*cdf0e10cSrcweir long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart ); 1035*cdf0e10cSrcweir aEditCursor.Left() = aEditCursor.Right() = nX; 1036*cdf0e10cSrcweir return aEditCursor; 1037*cdf0e10cSrcweir } 1038*cdf0e10cSrcweir 1039*cdf0e10cSrcweir long TextEngine::ImpGetXPos( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_Bool bPreferPortionStart ) 1040*cdf0e10cSrcweir { 1041*cdf0e10cSrcweir DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "ImpGetXPos muss richtig gerufen werden!" ); 1042*cdf0e10cSrcweir 1043*cdf0e10cSrcweir sal_Bool bDoPreferPortionStart = bPreferPortionStart; 1044*cdf0e10cSrcweir // Assure that the portion belongs to this line: 1045*cdf0e10cSrcweir if ( nIndex == pLine->GetStart() ) 1046*cdf0e10cSrcweir bDoPreferPortionStart = sal_True; 1047*cdf0e10cSrcweir else if ( nIndex == pLine->GetEnd() ) 1048*cdf0e10cSrcweir bDoPreferPortionStart = sal_False; 1049*cdf0e10cSrcweir 1050*cdf0e10cSrcweir TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); 1051*cdf0e10cSrcweir 1052*cdf0e10cSrcweir sal_uInt16 nTextPortionStart = 0; 1053*cdf0e10cSrcweir sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); 1054*cdf0e10cSrcweir 1055*cdf0e10cSrcweir DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " ); 1056*cdf0e10cSrcweir 1057*cdf0e10cSrcweir TETextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); 1058*cdf0e10cSrcweir 1059*cdf0e10cSrcweir long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion ); 1060*cdf0e10cSrcweir 1061*cdf0e10cSrcweir long nPortionTextWidth = pPortion->GetWidth(); 1062*cdf0e10cSrcweir 1063*cdf0e10cSrcweir if ( nTextPortionStart != nIndex ) 1064*cdf0e10cSrcweir { 1065*cdf0e10cSrcweir // Search within portion... 1066*cdf0e10cSrcweir if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) ) 1067*cdf0e10cSrcweir { 1068*cdf0e10cSrcweir // End of Portion 1069*cdf0e10cSrcweir if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) || 1070*cdf0e10cSrcweir ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || 1071*cdf0e10cSrcweir ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) 1072*cdf0e10cSrcweir { 1073*cdf0e10cSrcweir nX += nPortionTextWidth; 1074*cdf0e10cSrcweir if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().Count() ) ) 1075*cdf0e10cSrcweir { 1076*cdf0e10cSrcweir TETextPortion* pNextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion+1 ); 1077*cdf0e10cSrcweir if ( ( pNextPortion->GetKind() != PORTIONKIND_TAB ) && ( 1078*cdf0e10cSrcweir ( !IsRightToLeft() && pNextPortion->IsRightToLeft() ) || 1079*cdf0e10cSrcweir ( IsRightToLeft() && !pNextPortion->IsRightToLeft() ) ) ) 1080*cdf0e10cSrcweir { 1081*cdf0e10cSrcweir // nX += pNextPortion->GetWidth(); 1082*cdf0e10cSrcweir // End of the tab portion, use start of next for cursor pos 1083*cdf0e10cSrcweir DBG_ASSERT( !bPreferPortionStart, "ImpGetXPos - How can we this tab portion here???" ); 1084*cdf0e10cSrcweir nX = ImpGetXPos( nPara, pLine, nIndex, sal_True ); 1085*cdf0e10cSrcweir } 1086*cdf0e10cSrcweir 1087*cdf0e10cSrcweir } 1088*cdf0e10cSrcweir } 1089*cdf0e10cSrcweir } 1090*cdf0e10cSrcweir else if ( pPortion->GetKind() == PORTIONKIND_TEXT ) 1091*cdf0e10cSrcweir { 1092*cdf0e10cSrcweir DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new ImpGetXPos()" ); 1093*cdf0e10cSrcweir 1094*cdf0e10cSrcweir long nPosInPortion = (long)CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart ); 1095*cdf0e10cSrcweir 1096*cdf0e10cSrcweir if ( ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || 1097*cdf0e10cSrcweir ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) 1098*cdf0e10cSrcweir { 1099*cdf0e10cSrcweir nX += nPosInPortion; 1100*cdf0e10cSrcweir } 1101*cdf0e10cSrcweir else 1102*cdf0e10cSrcweir { 1103*cdf0e10cSrcweir nX += nPortionTextWidth - nPosInPortion; 1104*cdf0e10cSrcweir } 1105*cdf0e10cSrcweir } 1106*cdf0e10cSrcweir } 1107*cdf0e10cSrcweir else // if ( nIndex == pLine->GetStart() ) 1108*cdf0e10cSrcweir { 1109*cdf0e10cSrcweir if ( ( pPortion->GetKind() != PORTIONKIND_TAB ) && 1110*cdf0e10cSrcweir ( ( !IsRightToLeft() && pPortion->IsRightToLeft() ) || 1111*cdf0e10cSrcweir ( IsRightToLeft() && !pPortion->IsRightToLeft() ) ) ) 1112*cdf0e10cSrcweir { 1113*cdf0e10cSrcweir nX += nPortionTextWidth; 1114*cdf0e10cSrcweir } 1115*cdf0e10cSrcweir } 1116*cdf0e10cSrcweir 1117*cdf0e10cSrcweir return nX; 1118*cdf0e10cSrcweir } 1119*cdf0e10cSrcweir 1120*cdf0e10cSrcweir const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const 1121*cdf0e10cSrcweir { 1122*cdf0e10cSrcweir const TextAttrib* pAttr = NULL; 1123*cdf0e10cSrcweir const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich ); 1124*cdf0e10cSrcweir if ( pCharAttr ) 1125*cdf0e10cSrcweir pAttr = &pCharAttr->GetAttr(); 1126*cdf0e10cSrcweir return pAttr; 1127*cdf0e10cSrcweir } 1128*cdf0e10cSrcweir 1129*cdf0e10cSrcweir const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const 1130*cdf0e10cSrcweir { 1131*cdf0e10cSrcweir const TextCharAttrib* pAttr = NULL; 1132*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); 1133*cdf0e10cSrcweir if ( pNode && ( rPaM.GetIndex() < pNode->GetText().Len() ) ) 1134*cdf0e10cSrcweir pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() ); 1135*cdf0e10cSrcweir return pAttr; 1136*cdf0e10cSrcweir } 1137*cdf0e10cSrcweir 1138*cdf0e10cSrcweir sal_Bool TextEngine::HasAttrib( sal_uInt16 nWhich ) const 1139*cdf0e10cSrcweir { 1140*cdf0e10cSrcweir sal_Bool bAttr = sal_False; 1141*cdf0e10cSrcweir for ( sal_uLong n = mpDoc->GetNodes().Count(); --n && !bAttr; ) 1142*cdf0e10cSrcweir { 1143*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( n ); 1144*cdf0e10cSrcweir bAttr = pNode->GetCharAttribs().HasAttrib( nWhich ); 1145*cdf0e10cSrcweir } 1146*cdf0e10cSrcweir return bAttr; 1147*cdf0e10cSrcweir } 1148*cdf0e10cSrcweir 1149*cdf0e10cSrcweir TextPaM TextEngine::GetPaM( const Point& rDocPos, sal_Bool bSmart ) 1150*cdf0e10cSrcweir { 1151*cdf0e10cSrcweir DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: GetPaM" ); 1152*cdf0e10cSrcweir 1153*cdf0e10cSrcweir long nY = 0; 1154*cdf0e10cSrcweir for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ ) 1155*cdf0e10cSrcweir { 1156*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); 1157*cdf0e10cSrcweir long nTmpHeight = pPortion->GetLines().Count() * mnCharHeight; 1158*cdf0e10cSrcweir nY += nTmpHeight; 1159*cdf0e10cSrcweir if ( nY > rDocPos.Y() ) 1160*cdf0e10cSrcweir { 1161*cdf0e10cSrcweir nY -= nTmpHeight; 1162*cdf0e10cSrcweir Point aPosInPara( rDocPos ); 1163*cdf0e10cSrcweir aPosInPara.Y() -= nY; 1164*cdf0e10cSrcweir 1165*cdf0e10cSrcweir TextPaM aPaM( nPortion, 0 ); 1166*cdf0e10cSrcweir aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara, bSmart ); 1167*cdf0e10cSrcweir return aPaM; 1168*cdf0e10cSrcweir } 1169*cdf0e10cSrcweir } 1170*cdf0e10cSrcweir 1171*cdf0e10cSrcweir // Nicht gefunden - Dann den letzten sichtbare... 1172*cdf0e10cSrcweir sal_uLong nLastNode = mpDoc->GetNodes().Count() - 1; 1173*cdf0e10cSrcweir TextNode* pLast = mpDoc->GetNodes().GetObject( nLastNode ); 1174*cdf0e10cSrcweir return TextPaM( nLastNode, pLast->GetText().Len() ); 1175*cdf0e10cSrcweir } 1176*cdf0e10cSrcweir 1177*cdf0e10cSrcweir sal_uInt16 TextEngine::ImpFindIndex( sal_uLong nPortion, const Point& rPosInPara, sal_Bool bSmart ) 1178*cdf0e10cSrcweir { 1179*cdf0e10cSrcweir DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" ); 1180*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); 1181*cdf0e10cSrcweir 1182*cdf0e10cSrcweir sal_uInt16 nCurIndex = 0; 1183*cdf0e10cSrcweir 1184*cdf0e10cSrcweir long nY = 0; 1185*cdf0e10cSrcweir TextLine* pLine = 0; 1186*cdf0e10cSrcweir sal_uInt16 nLine; 1187*cdf0e10cSrcweir for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) 1188*cdf0e10cSrcweir { 1189*cdf0e10cSrcweir TextLine* pTmpLine = pPortion->GetLines().GetObject( nLine ); 1190*cdf0e10cSrcweir nY += mnCharHeight; 1191*cdf0e10cSrcweir if ( nY > rPosInPara.Y() ) // das war 'se 1192*cdf0e10cSrcweir { 1193*cdf0e10cSrcweir pLine = pTmpLine; 1194*cdf0e10cSrcweir break; // richtige Y-Position intressiert nicht 1195*cdf0e10cSrcweir } 1196*cdf0e10cSrcweir } 1197*cdf0e10cSrcweir DBG_ASSERT( pLine, "ImpFindIndex: pLine ?" ); 1198*cdf0e10cSrcweir 1199*cdf0e10cSrcweir nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X(), bSmart ); 1200*cdf0e10cSrcweir 1201*cdf0e10cSrcweir if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && 1202*cdf0e10cSrcweir ( pLine != pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1) ) ) 1203*cdf0e10cSrcweir { 1204*cdf0e10cSrcweir uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); 1205*cdf0e10cSrcweir sal_Int32 nCount = 1; 1206*cdf0e10cSrcweir nCurIndex = (sal_uInt16)xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); 1207*cdf0e10cSrcweir } 1208*cdf0e10cSrcweir return nCurIndex; 1209*cdf0e10cSrcweir } 1210*cdf0e10cSrcweir 1211*cdf0e10cSrcweir sal_uInt16 TextEngine::GetCharPos( sal_uLong nPortion, sal_uInt16 nLine, long nXPos, sal_Bool ) 1212*cdf0e10cSrcweir { 1213*cdf0e10cSrcweir 1214*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); 1215*cdf0e10cSrcweir TextLine* pLine = pPortion->GetLines().GetObject( nLine ); 1216*cdf0e10cSrcweir 1217*cdf0e10cSrcweir sal_uInt16 nCurIndex = pLine->GetStart(); 1218*cdf0e10cSrcweir 1219*cdf0e10cSrcweir long nTmpX = pLine->GetStartX(); 1220*cdf0e10cSrcweir if ( nXPos <= nTmpX ) 1221*cdf0e10cSrcweir return nCurIndex; 1222*cdf0e10cSrcweir 1223*cdf0e10cSrcweir for ( sal_uInt16 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ ) 1224*cdf0e10cSrcweir { 1225*cdf0e10cSrcweir TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( i ); 1226*cdf0e10cSrcweir nTmpX += pTextPortion->GetWidth(); 1227*cdf0e10cSrcweir 1228*cdf0e10cSrcweir if ( nTmpX > nXPos ) 1229*cdf0e10cSrcweir { 1230*cdf0e10cSrcweir if( pTextPortion->GetLen() > 1 ) 1231*cdf0e10cSrcweir { 1232*cdf0e10cSrcweir nTmpX -= pTextPortion->GetWidth(); // vor die Portion stellen 1233*cdf0e10cSrcweir // Optimieren: Kein GetTextBreak, wenn feste Fontbreite... 1234*cdf0e10cSrcweir Font aFont; 1235*cdf0e10cSrcweir SeekCursor( nPortion, nCurIndex+1, aFont, NULL ); 1236*cdf0e10cSrcweir mpRefDev->SetFont( aFont); 1237*cdf0e10cSrcweir long nPosInPortion = nXPos-nTmpX; 1238*cdf0e10cSrcweir if ( IsRightToLeft() != pTextPortion->IsRightToLeft() ) 1239*cdf0e10cSrcweir nPosInPortion = pTextPortion->GetWidth() - nPosInPortion; 1240*cdf0e10cSrcweir nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex ); 1241*cdf0e10cSrcweir // MT: GetTextBreak should assure that we are not withing a CTL cell... 1242*cdf0e10cSrcweir } 1243*cdf0e10cSrcweir return nCurIndex; 1244*cdf0e10cSrcweir } 1245*cdf0e10cSrcweir nCurIndex = nCurIndex + pTextPortion->GetLen(); 1246*cdf0e10cSrcweir } 1247*cdf0e10cSrcweir return nCurIndex; 1248*cdf0e10cSrcweir } 1249*cdf0e10cSrcweir 1250*cdf0e10cSrcweir 1251*cdf0e10cSrcweir sal_uLong TextEngine::GetTextHeight() const 1252*cdf0e10cSrcweir { 1253*cdf0e10cSrcweir DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" ); 1254*cdf0e10cSrcweir 1255*cdf0e10cSrcweir if ( !IsFormatted() && !IsFormatting() ) 1256*cdf0e10cSrcweir ((TextEngine*)this)->FormatAndUpdate(); 1257*cdf0e10cSrcweir 1258*cdf0e10cSrcweir return mnCurTextHeight; 1259*cdf0e10cSrcweir } 1260*cdf0e10cSrcweir 1261*cdf0e10cSrcweir sal_uLong TextEngine::GetTextHeight( sal_uLong nParagraph ) const 1262*cdf0e10cSrcweir { 1263*cdf0e10cSrcweir DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" ); 1264*cdf0e10cSrcweir 1265*cdf0e10cSrcweir if ( !IsFormatted() && !IsFormatting() ) 1266*cdf0e10cSrcweir ((TextEngine*)this)->FormatAndUpdate(); 1267*cdf0e10cSrcweir 1268*cdf0e10cSrcweir return CalcParaHeight( nParagraph ); 1269*cdf0e10cSrcweir } 1270*cdf0e10cSrcweir 1271*cdf0e10cSrcweir sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara ) 1272*cdf0e10cSrcweir { 1273*cdf0e10cSrcweir sal_uLong nParaWidth = 0; 1274*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); 1275*cdf0e10cSrcweir for ( sal_uInt16 nLine = pPortion->GetLines().Count(); nLine; ) 1276*cdf0e10cSrcweir { 1277*cdf0e10cSrcweir sal_uLong nLineWidth = 0; 1278*cdf0e10cSrcweir TextLine* pLine = pPortion->GetLines().GetObject( --nLine ); 1279*cdf0e10cSrcweir for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) 1280*cdf0e10cSrcweir { 1281*cdf0e10cSrcweir TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( nTP ); 1282*cdf0e10cSrcweir nLineWidth += pTextPortion->GetWidth(); 1283*cdf0e10cSrcweir } 1284*cdf0e10cSrcweir if ( nLineWidth > nParaWidth ) 1285*cdf0e10cSrcweir nParaWidth = nLineWidth; 1286*cdf0e10cSrcweir } 1287*cdf0e10cSrcweir return nParaWidth; 1288*cdf0e10cSrcweir } 1289*cdf0e10cSrcweir 1290*cdf0e10cSrcweir sal_uLong TextEngine::CalcTextWidth() 1291*cdf0e10cSrcweir { 1292*cdf0e10cSrcweir if ( !IsFormatted() && !IsFormatting() ) 1293*cdf0e10cSrcweir FormatAndUpdate(); 1294*cdf0e10cSrcweir 1295*cdf0e10cSrcweir if ( mnCurTextWidth == 0xFFFFFFFF ) 1296*cdf0e10cSrcweir { 1297*cdf0e10cSrcweir mnCurTextWidth = 0; 1298*cdf0e10cSrcweir for ( sal_uLong nPara = mpTEParaPortions->Count(); nPara; ) 1299*cdf0e10cSrcweir { 1300*cdf0e10cSrcweir sal_uLong nParaWidth = CalcTextWidth( --nPara ); 1301*cdf0e10cSrcweir if ( nParaWidth > mnCurTextWidth ) 1302*cdf0e10cSrcweir mnCurTextWidth = nParaWidth; 1303*cdf0e10cSrcweir } 1304*cdf0e10cSrcweir } 1305*cdf0e10cSrcweir return mnCurTextWidth+1;// Ein breiter, da in CreateLines bei >= umgebrochen wird. 1306*cdf0e10cSrcweir } 1307*cdf0e10cSrcweir 1308*cdf0e10cSrcweir sal_uLong TextEngine::CalcTextHeight() 1309*cdf0e10cSrcweir { 1310*cdf0e10cSrcweir DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: CalcTextHeight" ); 1311*cdf0e10cSrcweir 1312*cdf0e10cSrcweir sal_uLong nY = 0; 1313*cdf0e10cSrcweir for ( sal_uLong nPortion = mpTEParaPortions->Count(); nPortion; ) 1314*cdf0e10cSrcweir nY += CalcParaHeight( --nPortion ); 1315*cdf0e10cSrcweir return nY; 1316*cdf0e10cSrcweir } 1317*cdf0e10cSrcweir 1318*cdf0e10cSrcweir sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara, sal_uInt16 nPortionStart, sal_uInt16 nLen, const Font* pFont ) 1319*cdf0e10cSrcweir { 1320*cdf0e10cSrcweir // Innerhalb des Textes darf es keinen Portionwechsel (Attribut/Tab) geben! 1321*cdf0e10cSrcweir DBG_ASSERT( mpDoc->GetNodes().GetObject( nPara )->GetText().Search( '\t', nPortionStart ) >= (nPortionStart+nLen), "CalcTextWidth: Tab!" ); 1322*cdf0e10cSrcweir 1323*cdf0e10cSrcweir sal_uLong nWidth; 1324*cdf0e10cSrcweir if ( mnFixCharWidth100 ) 1325*cdf0e10cSrcweir { 1326*cdf0e10cSrcweir nWidth = (sal_uLong)nLen*mnFixCharWidth100/100; 1327*cdf0e10cSrcweir } 1328*cdf0e10cSrcweir else 1329*cdf0e10cSrcweir { 1330*cdf0e10cSrcweir if ( pFont ) 1331*cdf0e10cSrcweir { 1332*cdf0e10cSrcweir if ( !mpRefDev->GetFont().IsSameInstance( *pFont ) ) 1333*cdf0e10cSrcweir mpRefDev->SetFont( *pFont ); 1334*cdf0e10cSrcweir } 1335*cdf0e10cSrcweir else 1336*cdf0e10cSrcweir { 1337*cdf0e10cSrcweir Font aFont; 1338*cdf0e10cSrcweir SeekCursor( nPara, nPortionStart+1, aFont, NULL ); 1339*cdf0e10cSrcweir mpRefDev->SetFont( aFont ); 1340*cdf0e10cSrcweir } 1341*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 1342*cdf0e10cSrcweir nWidth = (sal_uLong)mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen ); 1343*cdf0e10cSrcweir 1344*cdf0e10cSrcweir } 1345*cdf0e10cSrcweir return nWidth; 1346*cdf0e10cSrcweir } 1347*cdf0e10cSrcweir 1348*cdf0e10cSrcweir 1349*cdf0e10cSrcweir sal_uInt16 TextEngine::GetLineCount( sal_uLong nParagraph ) const 1350*cdf0e10cSrcweir { 1351*cdf0e10cSrcweir DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" ); 1352*cdf0e10cSrcweir 1353*cdf0e10cSrcweir TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); 1354*cdf0e10cSrcweir if ( pPPortion ) 1355*cdf0e10cSrcweir return pPPortion->GetLines().Count(); 1356*cdf0e10cSrcweir 1357*cdf0e10cSrcweir return 0xFFFF; 1358*cdf0e10cSrcweir } 1359*cdf0e10cSrcweir 1360*cdf0e10cSrcweir sal_uInt16 TextEngine::GetLineLen( sal_uLong nParagraph, sal_uInt16 nLine ) const 1361*cdf0e10cSrcweir { 1362*cdf0e10cSrcweir DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" ); 1363*cdf0e10cSrcweir 1364*cdf0e10cSrcweir TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); 1365*cdf0e10cSrcweir if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) 1366*cdf0e10cSrcweir { 1367*cdf0e10cSrcweir TextLine* pLine = pPPortion->GetLines().GetObject( nLine ); 1368*cdf0e10cSrcweir return pLine->GetLen(); 1369*cdf0e10cSrcweir } 1370*cdf0e10cSrcweir 1371*cdf0e10cSrcweir return 0xFFFF; 1372*cdf0e10cSrcweir } 1373*cdf0e10cSrcweir 1374*cdf0e10cSrcweir sal_uLong TextEngine::CalcParaHeight( sal_uLong nParagraph ) const 1375*cdf0e10cSrcweir { 1376*cdf0e10cSrcweir sal_uLong nHeight = 0; 1377*cdf0e10cSrcweir 1378*cdf0e10cSrcweir TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); 1379*cdf0e10cSrcweir DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" ); 1380*cdf0e10cSrcweir if ( pPPortion ) 1381*cdf0e10cSrcweir nHeight = pPPortion->GetLines().Count() * mnCharHeight; 1382*cdf0e10cSrcweir 1383*cdf0e10cSrcweir return nHeight; 1384*cdf0e10cSrcweir } 1385*cdf0e10cSrcweir 1386*cdf0e10cSrcweir void TextEngine::UpdateSelections() 1387*cdf0e10cSrcweir { 1388*cdf0e10cSrcweir } 1389*cdf0e10cSrcweir 1390*cdf0e10cSrcweir Range TextEngine::GetInvalidYOffsets( sal_uLong nPortion ) 1391*cdf0e10cSrcweir { 1392*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); 1393*cdf0e10cSrcweir sal_uInt16 nLines = pTEParaPortion->GetLines().Count(); 1394*cdf0e10cSrcweir sal_uInt16 nLastInvalid, nFirstInvalid = 0; 1395*cdf0e10cSrcweir sal_uInt16 nLine; 1396*cdf0e10cSrcweir for ( nLine = 0; nLine < nLines; nLine++ ) 1397*cdf0e10cSrcweir { 1398*cdf0e10cSrcweir TextLine* pL = pTEParaPortion->GetLines().GetObject( nLine ); 1399*cdf0e10cSrcweir if ( pL->IsInvalid() ) 1400*cdf0e10cSrcweir { 1401*cdf0e10cSrcweir nFirstInvalid = nLine; 1402*cdf0e10cSrcweir break; 1403*cdf0e10cSrcweir } 1404*cdf0e10cSrcweir } 1405*cdf0e10cSrcweir 1406*cdf0e10cSrcweir for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ ) 1407*cdf0e10cSrcweir { 1408*cdf0e10cSrcweir TextLine* pL = pTEParaPortion->GetLines().GetObject( nLine ); 1409*cdf0e10cSrcweir if ( pL->IsValid() ) 1410*cdf0e10cSrcweir break; 1411*cdf0e10cSrcweir } 1412*cdf0e10cSrcweir 1413*cdf0e10cSrcweir if ( nLastInvalid >= nLines ) 1414*cdf0e10cSrcweir nLastInvalid = nLines-1; 1415*cdf0e10cSrcweir 1416*cdf0e10cSrcweir return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 ); 1417*cdf0e10cSrcweir } 1418*cdf0e10cSrcweir 1419*cdf0e10cSrcweir sal_uLong TextEngine::GetParagraphCount() const 1420*cdf0e10cSrcweir { 1421*cdf0e10cSrcweir return mpDoc->GetNodes().Count(); 1422*cdf0e10cSrcweir } 1423*cdf0e10cSrcweir 1424*cdf0e10cSrcweir void TextEngine::EnableUndo( sal_Bool bEnable ) 1425*cdf0e10cSrcweir { 1426*cdf0e10cSrcweir // Beim Umschalten des Modus Liste loeschen: 1427*cdf0e10cSrcweir if ( bEnable != IsUndoEnabled() ) 1428*cdf0e10cSrcweir ResetUndo(); 1429*cdf0e10cSrcweir 1430*cdf0e10cSrcweir mbUndoEnabled = bEnable; 1431*cdf0e10cSrcweir } 1432*cdf0e10cSrcweir 1433*cdf0e10cSrcweir ::svl::IUndoManager& TextEngine::GetUndoManager() 1434*cdf0e10cSrcweir { 1435*cdf0e10cSrcweir if ( !mpUndoManager ) 1436*cdf0e10cSrcweir mpUndoManager = new TextUndoManager( this ); 1437*cdf0e10cSrcweir return *mpUndoManager; 1438*cdf0e10cSrcweir } 1439*cdf0e10cSrcweir 1440*cdf0e10cSrcweir void TextEngine::UndoActionStart( sal_uInt16 nId ) 1441*cdf0e10cSrcweir { 1442*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 1443*cdf0e10cSrcweir { 1444*cdf0e10cSrcweir String aComment; 1445*cdf0e10cSrcweir // ... 1446*cdf0e10cSrcweir GetUndoManager().EnterListAction( aComment, XubString(), nId ); 1447*cdf0e10cSrcweir } 1448*cdf0e10cSrcweir } 1449*cdf0e10cSrcweir 1450*cdf0e10cSrcweir void TextEngine::UndoActionEnd() 1451*cdf0e10cSrcweir { 1452*cdf0e10cSrcweir if ( IsUndoEnabled() && !IsInUndo() ) 1453*cdf0e10cSrcweir GetUndoManager().LeaveListAction(); 1454*cdf0e10cSrcweir } 1455*cdf0e10cSrcweir 1456*cdf0e10cSrcweir void TextEngine::InsertUndo( TextUndo* pUndo, sal_Bool bTryMerge ) 1457*cdf0e10cSrcweir { 1458*cdf0e10cSrcweir DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" ); 1459*cdf0e10cSrcweir GetUndoManager().AddUndoAction( pUndo, bTryMerge ); 1460*cdf0e10cSrcweir } 1461*cdf0e10cSrcweir 1462*cdf0e10cSrcweir void TextEngine::ResetUndo() 1463*cdf0e10cSrcweir { 1464*cdf0e10cSrcweir if ( mpUndoManager ) 1465*cdf0e10cSrcweir mpUndoManager->Clear(); 1466*cdf0e10cSrcweir } 1467*cdf0e10cSrcweir 1468*cdf0e10cSrcweir void TextEngine::InsertContent( TextNode* pNode, sal_uLong nPara ) 1469*cdf0e10cSrcweir { 1470*cdf0e10cSrcweir DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " ); 1471*cdf0e10cSrcweir DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" ); 1472*cdf0e10cSrcweir TEParaPortion* pNew = new TEParaPortion( pNode ); 1473*cdf0e10cSrcweir mpTEParaPortions->Insert( pNew, nPara ); 1474*cdf0e10cSrcweir mpDoc->GetNodes().Insert( pNode, nPara ); 1475*cdf0e10cSrcweir ImpParagraphInserted( nPara ); 1476*cdf0e10cSrcweir } 1477*cdf0e10cSrcweir 1478*cdf0e10cSrcweir TextPaM TextEngine::SplitContent( sal_uLong nNode, sal_uInt16 nSepPos ) 1479*cdf0e10cSrcweir { 1480*cdf0e10cSrcweir #ifdef DBG_UTIL 1481*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); 1482*cdf0e10cSrcweir DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" ); 1483*cdf0e10cSrcweir DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" ); 1484*cdf0e10cSrcweir DBG_ASSERT( nSepPos <= pNode->GetText().Len(), "Index im Wald: SplitContent" ); 1485*cdf0e10cSrcweir #endif 1486*cdf0e10cSrcweir TextPaM aPaM( nNode, nSepPos ); 1487*cdf0e10cSrcweir return ImpInsertParaBreak( aPaM ); 1488*cdf0e10cSrcweir } 1489*cdf0e10cSrcweir 1490*cdf0e10cSrcweir TextPaM TextEngine::ConnectContents( sal_uLong nLeftNode ) 1491*cdf0e10cSrcweir { 1492*cdf0e10cSrcweir DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" ); 1493*cdf0e10cSrcweir return ImpConnectParagraphs( nLeftNode, nLeftNode+1 ); 1494*cdf0e10cSrcweir } 1495*cdf0e10cSrcweir 1496*cdf0e10cSrcweir void TextEngine::SeekCursor( sal_uLong nPara, sal_uInt16 nPos, Font& rFont, OutputDevice* pOutDev ) 1497*cdf0e10cSrcweir { 1498*cdf0e10cSrcweir rFont = maFont; 1499*cdf0e10cSrcweir if ( pOutDev ) 1500*cdf0e10cSrcweir pOutDev->SetTextColor( maTextColor ); 1501*cdf0e10cSrcweir 1502*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 1503*cdf0e10cSrcweir sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); 1504*cdf0e10cSrcweir for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) 1505*cdf0e10cSrcweir { 1506*cdf0e10cSrcweir TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); 1507*cdf0e10cSrcweir if ( pAttrib->GetStart() > nPos ) 1508*cdf0e10cSrcweir break; 1509*cdf0e10cSrcweir 1510*cdf0e10cSrcweir // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen! 1511*cdf0e10cSrcweir // Leere Attribute werden beruecksichtigt( verwendet), da diese 1512*cdf0e10cSrcweir // gerade eingestellt wurden. 1513*cdf0e10cSrcweir // 12.4.95: Doch keine Leeren Attribute verwenden: 1514*cdf0e10cSrcweir // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font 1515*cdf0e10cSrcweir // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam. 1516*cdf0e10cSrcweir if ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) ) 1517*cdf0e10cSrcweir || !pNode->GetText().Len() ) 1518*cdf0e10cSrcweir { 1519*cdf0e10cSrcweir if ( pAttrib->Which() != TEXTATTR_FONTCOLOR ) 1520*cdf0e10cSrcweir { 1521*cdf0e10cSrcweir pAttrib->GetAttr().SetFont( rFont ); 1522*cdf0e10cSrcweir } 1523*cdf0e10cSrcweir else 1524*cdf0e10cSrcweir { 1525*cdf0e10cSrcweir if ( pOutDev ) 1526*cdf0e10cSrcweir pOutDev->SetTextColor( ((TextAttribFontColor&)pAttrib->GetAttr()).GetColor() ); 1527*cdf0e10cSrcweir } 1528*cdf0e10cSrcweir } 1529*cdf0e10cSrcweir } 1530*cdf0e10cSrcweir 1531*cdf0e10cSrcweir if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) && 1532*cdf0e10cSrcweir ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) ) 1533*cdf0e10cSrcweir { 1534*cdf0e10cSrcweir sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ]; 1535*cdf0e10cSrcweir if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE ) 1536*cdf0e10cSrcweir rFont.SetUnderline( UNDERLINE_SINGLE ); 1537*cdf0e10cSrcweir else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE ) 1538*cdf0e10cSrcweir rFont.SetUnderline( UNDERLINE_BOLD ); 1539*cdf0e10cSrcweir else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ) 1540*cdf0e10cSrcweir rFont.SetUnderline( UNDERLINE_DOTTED ); 1541*cdf0e10cSrcweir else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ) 1542*cdf0e10cSrcweir rFont.SetUnderline( UNDERLINE_DOTTED ); 1543*cdf0e10cSrcweir if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT ) 1544*cdf0e10cSrcweir rFont.SetColor( Color( COL_RED ) ); 1545*cdf0e10cSrcweir else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT ) 1546*cdf0e10cSrcweir rFont.SetColor( Color( COL_LIGHTGRAY ) ); 1547*cdf0e10cSrcweir if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) 1548*cdf0e10cSrcweir { 1549*cdf0e10cSrcweir const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); 1550*cdf0e10cSrcweir rFont.SetColor( rStyleSettings.GetHighlightTextColor() ); 1551*cdf0e10cSrcweir rFont.SetFillColor( rStyleSettings.GetHighlightColor() ); 1552*cdf0e10cSrcweir rFont.SetTransparent( sal_False ); 1553*cdf0e10cSrcweir } 1554*cdf0e10cSrcweir else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE ) 1555*cdf0e10cSrcweir { 1556*cdf0e10cSrcweir rFont.SetUnderline( UNDERLINE_WAVE ); 1557*cdf0e10cSrcweir // if( pOut ) 1558*cdf0e10cSrcweir // pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) ); 1559*cdf0e10cSrcweir } 1560*cdf0e10cSrcweir } 1561*cdf0e10cSrcweir } 1562*cdf0e10cSrcweir 1563*cdf0e10cSrcweir void TextEngine::SetUpdateMode( sal_Bool bUp, TextView* pCurView, sal_Bool bForceUpdate ) 1564*cdf0e10cSrcweir { 1565*cdf0e10cSrcweir sal_Bool bChanged = ( GetUpdateMode() != bUp ); 1566*cdf0e10cSrcweir 1567*cdf0e10cSrcweir mbUpdate = bUp; 1568*cdf0e10cSrcweir if ( mbUpdate && ( bChanged || bForceUpdate ) ) 1569*cdf0e10cSrcweir FormatAndUpdate( pCurView ); 1570*cdf0e10cSrcweir } 1571*cdf0e10cSrcweir 1572*cdf0e10cSrcweir void TextEngine::FormatAndUpdate( TextView* pCurView ) 1573*cdf0e10cSrcweir { 1574*cdf0e10cSrcweir if ( mbDowning ) 1575*cdf0e10cSrcweir return ; 1576*cdf0e10cSrcweir 1577*cdf0e10cSrcweir if ( IsInUndo() ) 1578*cdf0e10cSrcweir IdleFormatAndUpdate( pCurView ); 1579*cdf0e10cSrcweir else 1580*cdf0e10cSrcweir { 1581*cdf0e10cSrcweir FormatDoc(); 1582*cdf0e10cSrcweir UpdateViews( pCurView ); 1583*cdf0e10cSrcweir } 1584*cdf0e10cSrcweir } 1585*cdf0e10cSrcweir 1586*cdf0e10cSrcweir 1587*cdf0e10cSrcweir void TextEngine::IdleFormatAndUpdate( TextView* pCurView, sal_uInt16 nMaxTimerRestarts ) 1588*cdf0e10cSrcweir { 1589*cdf0e10cSrcweir mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts ); 1590*cdf0e10cSrcweir } 1591*cdf0e10cSrcweir 1592*cdf0e10cSrcweir void TextEngine::TextModified() 1593*cdf0e10cSrcweir { 1594*cdf0e10cSrcweir mbFormatted = sal_False; 1595*cdf0e10cSrcweir mbModified = sal_True; 1596*cdf0e10cSrcweir } 1597*cdf0e10cSrcweir 1598*cdf0e10cSrcweir void TextEngine::UpdateViews( TextView* pCurView ) 1599*cdf0e10cSrcweir { 1600*cdf0e10cSrcweir if ( !GetUpdateMode() || IsFormatting() || maInvalidRec.IsEmpty() ) 1601*cdf0e10cSrcweir return; 1602*cdf0e10cSrcweir 1603*cdf0e10cSrcweir DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" ); 1604*cdf0e10cSrcweir 1605*cdf0e10cSrcweir for ( sal_uInt16 nView = 0; nView < mpViews->Count(); nView++ ) 1606*cdf0e10cSrcweir { 1607*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( nView ); 1608*cdf0e10cSrcweir pView->HideCursor(); 1609*cdf0e10cSrcweir 1610*cdf0e10cSrcweir Rectangle aClipRec( maInvalidRec ); 1611*cdf0e10cSrcweir Size aOutSz = pView->GetWindow()->GetOutputSizePixel(); 1612*cdf0e10cSrcweir Rectangle aVisArea( pView->GetStartDocPos(), aOutSz ); 1613*cdf0e10cSrcweir aClipRec.Intersection( aVisArea ); 1614*cdf0e10cSrcweir if ( !aClipRec.IsEmpty() ) 1615*cdf0e10cSrcweir { 1616*cdf0e10cSrcweir // in Fensterkoordinaten umwandeln.... 1617*cdf0e10cSrcweir Point aNewPos = pView->GetWindowPos( aClipRec.TopLeft() ); 1618*cdf0e10cSrcweir if ( IsRightToLeft() ) 1619*cdf0e10cSrcweir aNewPos.X() -= aOutSz.Width() - 1; 1620*cdf0e10cSrcweir aClipRec.SetPos( aNewPos ); 1621*cdf0e10cSrcweir 1622*cdf0e10cSrcweir if ( pView == pCurView ) 1623*cdf0e10cSrcweir pView->ImpPaint( aClipRec, !pView->GetWindow()->IsPaintTransparent() ); 1624*cdf0e10cSrcweir else 1625*cdf0e10cSrcweir pView->GetWindow()->Invalidate( aClipRec ); 1626*cdf0e10cSrcweir } 1627*cdf0e10cSrcweir } 1628*cdf0e10cSrcweir 1629*cdf0e10cSrcweir if ( pCurView ) 1630*cdf0e10cSrcweir { 1631*cdf0e10cSrcweir pCurView->ShowCursor( pCurView->IsAutoScroll() ); 1632*cdf0e10cSrcweir } 1633*cdf0e10cSrcweir 1634*cdf0e10cSrcweir maInvalidRec = Rectangle(); 1635*cdf0e10cSrcweir } 1636*cdf0e10cSrcweir 1637*cdf0e10cSrcweir IMPL_LINK( TextEngine, IdleFormatHdl, Timer *, EMPTYARG ) 1638*cdf0e10cSrcweir { 1639*cdf0e10cSrcweir FormatAndUpdate( mpIdleFormatter->GetView() ); 1640*cdf0e10cSrcweir return 0; 1641*cdf0e10cSrcweir } 1642*cdf0e10cSrcweir 1643*cdf0e10cSrcweir void TextEngine::CheckIdleFormatter() 1644*cdf0e10cSrcweir { 1645*cdf0e10cSrcweir mpIdleFormatter->ForceTimeout(); 1646*cdf0e10cSrcweir } 1647*cdf0e10cSrcweir 1648*cdf0e10cSrcweir void TextEngine::FormatFullDoc() 1649*cdf0e10cSrcweir { 1650*cdf0e10cSrcweir for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ ) 1651*cdf0e10cSrcweir { 1652*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); sal_uInt16 nLen = pTEParaPortion->GetNode()->GetText().Len(); 1653*cdf0e10cSrcweir pTEParaPortion->MarkSelectionInvalid( 0, nLen ); 1654*cdf0e10cSrcweir } 1655*cdf0e10cSrcweir mbFormatted = sal_False; 1656*cdf0e10cSrcweir FormatDoc(); 1657*cdf0e10cSrcweir } 1658*cdf0e10cSrcweir 1659*cdf0e10cSrcweir void TextEngine::FormatDoc() 1660*cdf0e10cSrcweir { 1661*cdf0e10cSrcweir if ( IsFormatted() || !GetUpdateMode() || IsFormatting() ) 1662*cdf0e10cSrcweir return; 1663*cdf0e10cSrcweir 1664*cdf0e10cSrcweir mbIsFormatting = sal_True; 1665*cdf0e10cSrcweir mbHasMultiLineParas = sal_False; 1666*cdf0e10cSrcweir 1667*cdf0e10cSrcweir long nY = 0; 1668*cdf0e10cSrcweir sal_Bool bGrow = sal_False; 1669*cdf0e10cSrcweir 1670*cdf0e10cSrcweir maInvalidRec = Rectangle(); // leermachen 1671*cdf0e10cSrcweir for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ ) 1672*cdf0e10cSrcweir { 1673*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 1674*cdf0e10cSrcweir if ( pTEParaPortion->IsInvalid() ) 1675*cdf0e10cSrcweir { 1676*cdf0e10cSrcweir sal_uLong nOldParaWidth = 0xFFFFFFFF; 1677*cdf0e10cSrcweir if ( mnCurTextWidth != 0xFFFFFFFF ) 1678*cdf0e10cSrcweir nOldParaWidth = CalcTextWidth( nPara ); 1679*cdf0e10cSrcweir 1680*cdf0e10cSrcweir ImpFormattingParagraph( nPara ); 1681*cdf0e10cSrcweir 1682*cdf0e10cSrcweir if ( CreateLines( nPara ) ) 1683*cdf0e10cSrcweir bGrow = sal_True; 1684*cdf0e10cSrcweir 1685*cdf0e10cSrcweir // InvalidRec nur einmal setzen... 1686*cdf0e10cSrcweir if ( maInvalidRec.IsEmpty() ) 1687*cdf0e10cSrcweir { 1688*cdf0e10cSrcweir // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()... 1689*cdf0e10cSrcweir long nWidth = (long)mnMaxTextWidth; 1690*cdf0e10cSrcweir if ( !nWidth ) 1691*cdf0e10cSrcweir nWidth = 0x7FFFFFFF; 1692*cdf0e10cSrcweir Range aInvRange( GetInvalidYOffsets( nPara ) ); 1693*cdf0e10cSrcweir maInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ), 1694*cdf0e10cSrcweir Size( nWidth, aInvRange.Len() ) ); 1695*cdf0e10cSrcweir } 1696*cdf0e10cSrcweir else 1697*cdf0e10cSrcweir { 1698*cdf0e10cSrcweir maInvalidRec.Bottom() = nY + CalcParaHeight( nPara ); 1699*cdf0e10cSrcweir } 1700*cdf0e10cSrcweir 1701*cdf0e10cSrcweir if ( mnCurTextWidth != 0xFFFFFFFF ) 1702*cdf0e10cSrcweir { 1703*cdf0e10cSrcweir sal_uLong nNewParaWidth = CalcTextWidth( nPara ); 1704*cdf0e10cSrcweir if ( nNewParaWidth >= mnCurTextWidth ) 1705*cdf0e10cSrcweir mnCurTextWidth = nNewParaWidth; 1706*cdf0e10cSrcweir else if ( ( nOldParaWidth != 0xFFFFFFFF ) && ( nOldParaWidth >= mnCurTextWidth ) ) 1707*cdf0e10cSrcweir mnCurTextWidth = 0xFFFFFFFF; 1708*cdf0e10cSrcweir } 1709*cdf0e10cSrcweir } 1710*cdf0e10cSrcweir else if ( bGrow ) 1711*cdf0e10cSrcweir { 1712*cdf0e10cSrcweir maInvalidRec.Bottom() = nY + CalcParaHeight( nPara ); 1713*cdf0e10cSrcweir } 1714*cdf0e10cSrcweir nY += CalcParaHeight( nPara ); 1715*cdf0e10cSrcweir if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().Count() > 1 ) 1716*cdf0e10cSrcweir mbHasMultiLineParas = sal_True; 1717*cdf0e10cSrcweir } 1718*cdf0e10cSrcweir 1719*cdf0e10cSrcweir if ( !maInvalidRec.IsEmpty() ) 1720*cdf0e10cSrcweir { 1721*cdf0e10cSrcweir sal_uLong nNewHeight = CalcTextHeight(); 1722*cdf0e10cSrcweir long nDiff = nNewHeight - mnCurTextHeight; 1723*cdf0e10cSrcweir if ( nNewHeight < mnCurTextHeight ) 1724*cdf0e10cSrcweir { 1725*cdf0e10cSrcweir maInvalidRec.Bottom() = (long)Max( nNewHeight, mnCurTextHeight ); 1726*cdf0e10cSrcweir if ( maInvalidRec.IsEmpty() ) 1727*cdf0e10cSrcweir { 1728*cdf0e10cSrcweir maInvalidRec.Top() = 0; 1729*cdf0e10cSrcweir // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt. 1730*cdf0e10cSrcweir maInvalidRec.Left() = 0; 1731*cdf0e10cSrcweir maInvalidRec.Right() = mnMaxTextWidth; 1732*cdf0e10cSrcweir } 1733*cdf0e10cSrcweir } 1734*cdf0e10cSrcweir 1735*cdf0e10cSrcweir mnCurTextHeight = nNewHeight; 1736*cdf0e10cSrcweir if ( nDiff ) 1737*cdf0e10cSrcweir { 1738*cdf0e10cSrcweir mbFormatted = sal_True; 1739*cdf0e10cSrcweir ImpTextHeightChanged(); 1740*cdf0e10cSrcweir } 1741*cdf0e10cSrcweir } 1742*cdf0e10cSrcweir 1743*cdf0e10cSrcweir mbIsFormatting = sal_False; 1744*cdf0e10cSrcweir mbFormatted = sal_True; 1745*cdf0e10cSrcweir 1746*cdf0e10cSrcweir ImpTextFormatted(); 1747*cdf0e10cSrcweir } 1748*cdf0e10cSrcweir 1749*cdf0e10cSrcweir void TextEngine::CreateAndInsertEmptyLine( sal_uLong nPara ) 1750*cdf0e10cSrcweir { 1751*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 1752*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 1753*cdf0e10cSrcweir 1754*cdf0e10cSrcweir TextLine* pTmpLine = new TextLine; 1755*cdf0e10cSrcweir pTmpLine->SetStart( pNode->GetText().Len() ); 1756*cdf0e10cSrcweir pTmpLine->SetEnd( pTmpLine->GetStart() ); 1757*cdf0e10cSrcweir pTEParaPortion->GetLines().Insert( pTmpLine, pTEParaPortion->GetLines().Count() ); 1758*cdf0e10cSrcweir 1759*cdf0e10cSrcweir if ( ImpGetAlign() == TXTALIGN_CENTER ) 1760*cdf0e10cSrcweir pTmpLine->SetStartX( (short)(mnMaxTextWidth / 2) ); 1761*cdf0e10cSrcweir else if ( ImpGetAlign() == TXTALIGN_RIGHT ) 1762*cdf0e10cSrcweir pTmpLine->SetStartX( (short)mnMaxTextWidth ); 1763*cdf0e10cSrcweir else 1764*cdf0e10cSrcweir pTmpLine->SetStartX( mpDoc->GetLeftMargin() ); 1765*cdf0e10cSrcweir 1766*cdf0e10cSrcweir sal_Bool bLineBreak = pNode->GetText().Len() ? sal_True : sal_False; 1767*cdf0e10cSrcweir 1768*cdf0e10cSrcweir TETextPortion* pDummyPortion = new TETextPortion( 0 ); 1769*cdf0e10cSrcweir pDummyPortion->GetWidth() = 0; 1770*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().Insert( pDummyPortion, pTEParaPortion->GetTextPortions().Count() ); 1771*cdf0e10cSrcweir 1772*cdf0e10cSrcweir if ( bLineBreak == sal_True ) 1773*cdf0e10cSrcweir { 1774*cdf0e10cSrcweir // -2: Die neue ist bereits eingefuegt. 1775*cdf0e10cSrcweir #ifdef DBG_UTIL 1776*cdf0e10cSrcweir TextLine* pLastLine = pTEParaPortion->GetLines().GetObject( pTEParaPortion->GetLines().Count()-2 ); 1777*cdf0e10cSrcweir DBG_ASSERT( pLastLine, "Weicher Umbruch, keine Zeile ?!" ); 1778*cdf0e10cSrcweir #endif 1779*cdf0e10cSrcweir sal_uInt16 nPos = (sal_uInt16) pTEParaPortion->GetTextPortions().Count() - 1 ; 1780*cdf0e10cSrcweir pTmpLine->SetStartPortion( nPos ); 1781*cdf0e10cSrcweir pTmpLine->SetEndPortion( nPos ); 1782*cdf0e10cSrcweir } 1783*cdf0e10cSrcweir } 1784*cdf0e10cSrcweir 1785*cdf0e10cSrcweir void TextEngine::ImpBreakLine( sal_uLong nPara, TextLine* pLine, TETextPortion*, sal_uInt16 nPortionStart, long nRemainingWidth ) 1786*cdf0e10cSrcweir { 1787*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 1788*cdf0e10cSrcweir 1789*cdf0e10cSrcweir // Font sollte noch eingestellt sein. 1790*cdf0e10cSrcweir sal_uInt16 nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart ); 1791*cdf0e10cSrcweir 1792*cdf0e10cSrcweir DBG_ASSERT( nMaxBreakPos < pNode->GetText().Len(), "Break?!" ); 1793*cdf0e10cSrcweir 1794*cdf0e10cSrcweir if ( nMaxBreakPos == STRING_LEN ) // GetTextBreak() ist anderer Auffassung als GetTextSize() 1795*cdf0e10cSrcweir nMaxBreakPos = pNode->GetText().Len() - 1; 1796*cdf0e10cSrcweir 1797*cdf0e10cSrcweir uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); 1798*cdf0e10cSrcweir i18n::LineBreakHyphenationOptions aHyphOptions( NULL, uno::Sequence< beans::PropertyValue >(), 1 ); 1799*cdf0e10cSrcweir 1800*cdf0e10cSrcweir i18n::LineBreakUserOptions aUserOptions; 1801*cdf0e10cSrcweir aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine; 1802*cdf0e10cSrcweir aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine; 1803*cdf0e10cSrcweir aUserOptions.applyForbiddenRules = sal_True; 1804*cdf0e10cSrcweir aUserOptions.allowPunctuationOutsideMargin = sal_False; 1805*cdf0e10cSrcweir aUserOptions.allowHyphenateEnglish = sal_False; 1806*cdf0e10cSrcweir 1807*cdf0e10cSrcweir static const com::sun::star::lang::Locale aDefLocale; 1808*cdf0e10cSrcweir i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions ); 1809*cdf0e10cSrcweir sal_uInt16 nBreakPos = (sal_uInt16)aLBR.breakIndex; 1810*cdf0e10cSrcweir if ( nBreakPos <= pLine->GetStart() ) 1811*cdf0e10cSrcweir { 1812*cdf0e10cSrcweir nBreakPos = nMaxBreakPos; 1813*cdf0e10cSrcweir if ( nBreakPos <= pLine->GetStart() ) 1814*cdf0e10cSrcweir nBreakPos = pLine->GetStart() + 1; // Sonst Endlosschleife! 1815*cdf0e10cSrcweir } 1816*cdf0e10cSrcweir 1817*cdf0e10cSrcweir 1818*cdf0e10cSrcweir // die angeknackste Portion ist die End-Portion 1819*cdf0e10cSrcweir pLine->SetEnd( nBreakPos ); 1820*cdf0e10cSrcweir sal_uInt16 nEndPortion = SplitTextPortion( nPara, nBreakPos ); 1821*cdf0e10cSrcweir 1822*cdf0e10cSrcweir sal_Bool bBlankSeparator = ( ( nBreakPos >= pLine->GetStart() ) && 1823*cdf0e10cSrcweir ( pNode->GetText().GetChar( nBreakPos ) == ' ' ) ) ? sal_True : sal_False; 1824*cdf0e10cSrcweir if ( bBlankSeparator ) 1825*cdf0e10cSrcweir { 1826*cdf0e10cSrcweir // Blanks am Zeilenende generell unterdruecken... 1827*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 1828*cdf0e10cSrcweir TETextPortion* pTP = pTEParaPortion->GetTextPortions().GetObject( nEndPortion ); 1829*cdf0e10cSrcweir DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); 1830*cdf0e10cSrcweir pTP->GetWidth() = (long)CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 ); 1831*cdf0e10cSrcweir } 1832*cdf0e10cSrcweir pLine->SetEndPortion( nEndPortion ); 1833*cdf0e10cSrcweir } 1834*cdf0e10cSrcweir 1835*cdf0e10cSrcweir sal_uInt16 TextEngine::SplitTextPortion( sal_uLong nPara, sal_uInt16 nPos ) 1836*cdf0e10cSrcweir { 1837*cdf0e10cSrcweir 1838*cdf0e10cSrcweir // Die Portion bei nPos wird geplittet, wenn bei nPos nicht 1839*cdf0e10cSrcweir // sowieso ein Wechsel ist 1840*cdf0e10cSrcweir if ( nPos == 0 ) 1841*cdf0e10cSrcweir return 0; 1842*cdf0e10cSrcweir 1843*cdf0e10cSrcweir sal_uInt16 nSplitPortion; 1844*cdf0e10cSrcweir sal_uInt16 nTmpPos = 0; 1845*cdf0e10cSrcweir TETextPortion* pTextPortion = 0; 1846*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 1847*cdf0e10cSrcweir sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().Count(); 1848*cdf0e10cSrcweir for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ ) 1849*cdf0e10cSrcweir { 1850*cdf0e10cSrcweir TETextPortion* pTP = pTEParaPortion->GetTextPortions().GetObject(nSplitPortion); 1851*cdf0e10cSrcweir nTmpPos = nTmpPos + pTP->GetLen(); 1852*cdf0e10cSrcweir if ( nTmpPos >= nPos ) 1853*cdf0e10cSrcweir { 1854*cdf0e10cSrcweir if ( nTmpPos == nPos ) // dann braucht nichts geteilt werden 1855*cdf0e10cSrcweir return nSplitPortion; 1856*cdf0e10cSrcweir pTextPortion = pTP; 1857*cdf0e10cSrcweir break; 1858*cdf0e10cSrcweir } 1859*cdf0e10cSrcweir } 1860*cdf0e10cSrcweir 1861*cdf0e10cSrcweir DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" ); 1862*cdf0e10cSrcweir 1863*cdf0e10cSrcweir sal_uInt16 nOverlapp = nTmpPos - nPos; 1864*cdf0e10cSrcweir pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp; 1865*cdf0e10cSrcweir TETextPortion* pNewPortion = new TETextPortion( nOverlapp ); 1866*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().Insert( pNewPortion, nSplitPortion+1 ); 1867*cdf0e10cSrcweir pTextPortion->GetWidth() = (long)CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() ); 1868*cdf0e10cSrcweir 1869*cdf0e10cSrcweir return nSplitPortion; 1870*cdf0e10cSrcweir } 1871*cdf0e10cSrcweir 1872*cdf0e10cSrcweir void TextEngine::CreateTextPortions( sal_uLong nPara, sal_uInt16 nStartPos ) 1873*cdf0e10cSrcweir { 1874*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 1875*cdf0e10cSrcweir TextNode* pNode = pTEParaPortion->GetNode(); 1876*cdf0e10cSrcweir DBG_ASSERT( pNode->GetText().Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" ); 1877*cdf0e10cSrcweir 1878*cdf0e10cSrcweir TESortedPositions aPositions; 1879*cdf0e10cSrcweir sal_uLong nZero = 0; 1880*cdf0e10cSrcweir aPositions.Insert( nZero ); 1881*cdf0e10cSrcweir 1882*cdf0e10cSrcweir sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); 1883*cdf0e10cSrcweir for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) 1884*cdf0e10cSrcweir { 1885*cdf0e10cSrcweir TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); 1886*cdf0e10cSrcweir 1887*cdf0e10cSrcweir // Start und Ende in das Array eintragen... 1888*cdf0e10cSrcweir // Die InsertMethode laesst keine doppelten Werte zu.... 1889*cdf0e10cSrcweir aPositions.Insert( pAttrib->GetStart() ); 1890*cdf0e10cSrcweir aPositions.Insert( pAttrib->GetEnd() ); 1891*cdf0e10cSrcweir } 1892*cdf0e10cSrcweir aPositions.Insert( pNode->GetText().Len() ); 1893*cdf0e10cSrcweir 1894*cdf0e10cSrcweir const TEWritingDirectionInfos& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos(); 1895*cdf0e10cSrcweir for ( sal_uInt16 nD = 0; nD < rWritingDirections.Count(); nD++ ) 1896*cdf0e10cSrcweir aPositions.Insert( rWritingDirections[nD].nStartPos ); 1897*cdf0e10cSrcweir 1898*cdf0e10cSrcweir if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) ) 1899*cdf0e10cSrcweir { 1900*cdf0e10cSrcweir sal_uInt16 nLastAttr = 0xFFFF; 1901*cdf0e10cSrcweir for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ ) 1902*cdf0e10cSrcweir { 1903*cdf0e10cSrcweir if ( mpIMEInfos->pAttribs[n] != nLastAttr ) 1904*cdf0e10cSrcweir { 1905*cdf0e10cSrcweir aPositions.Insert( mpIMEInfos->aPos.GetIndex() + n ); 1906*cdf0e10cSrcweir nLastAttr = mpIMEInfos->pAttribs[n]; 1907*cdf0e10cSrcweir } 1908*cdf0e10cSrcweir } 1909*cdf0e10cSrcweir } 1910*cdf0e10cSrcweir 1911*cdf0e10cSrcweir sal_uInt16 nTabPos = pNode->GetText().Search( '\t', 0 ); 1912*cdf0e10cSrcweir while ( nTabPos != STRING_NOTFOUND ) 1913*cdf0e10cSrcweir { 1914*cdf0e10cSrcweir aPositions.Insert( nTabPos ); 1915*cdf0e10cSrcweir aPositions.Insert( nTabPos + 1 ); 1916*cdf0e10cSrcweir nTabPos = pNode->GetText().Search( '\t', nTabPos+1 ); 1917*cdf0e10cSrcweir } 1918*cdf0e10cSrcweir 1919*cdf0e10cSrcweir // Ab ... loeschen: 1920*cdf0e10cSrcweir // Leider muss die Anzahl der TextPortions mit aPositions.Count() 1921*cdf0e10cSrcweir // nicht uebereinstimmen, da evtl. Zeilenumbrueche... 1922*cdf0e10cSrcweir sal_uInt16 nPortionStart = 0; 1923*cdf0e10cSrcweir sal_uInt16 nInvPortion = 0; 1924*cdf0e10cSrcweir sal_uInt16 nP; 1925*cdf0e10cSrcweir for ( nP = 0; nP < pTEParaPortion->GetTextPortions().Count(); nP++ ) 1926*cdf0e10cSrcweir { 1927*cdf0e10cSrcweir TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions().GetObject(nP); 1928*cdf0e10cSrcweir nPortionStart = nPortionStart + pTmpPortion->GetLen(); 1929*cdf0e10cSrcweir if ( nPortionStart >= nStartPos ) 1930*cdf0e10cSrcweir { 1931*cdf0e10cSrcweir nPortionStart = nPortionStart - pTmpPortion->GetLen(); 1932*cdf0e10cSrcweir nInvPortion = nP; 1933*cdf0e10cSrcweir break; 1934*cdf0e10cSrcweir } 1935*cdf0e10cSrcweir } 1936*cdf0e10cSrcweir DBG_ASSERT( nP < pTEParaPortion->GetTextPortions().Count() || !pTEParaPortion->GetTextPortions().Count(), "Nichts zum loeschen: CreateTextPortions" ); 1937*cdf0e10cSrcweir if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen() > nStartPos ) ) 1938*cdf0e10cSrcweir { 1939*cdf0e10cSrcweir // lieber eine davor... 1940*cdf0e10cSrcweir // Aber nur wenn es mitten in der Portion war, sonst ist es evtl. 1941*cdf0e10cSrcweir // die einzige in der Zeile davor ! 1942*cdf0e10cSrcweir nInvPortion--; 1943*cdf0e10cSrcweir nPortionStart = nPortionStart - pTEParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen(); 1944*cdf0e10cSrcweir } 1945*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion ); 1946*cdf0e10cSrcweir 1947*cdf0e10cSrcweir // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein: 1948*cdf0e10cSrcweir aPositions.Insert( nPortionStart ); 1949*cdf0e10cSrcweir 1950*cdf0e10cSrcweir sal_uInt16 nInvPos; 1951*cdf0e10cSrcweir #ifdef DBG_UTIL 1952*cdf0e10cSrcweir sal_Bool bFound = 1953*cdf0e10cSrcweir #endif 1954*cdf0e10cSrcweir aPositions.Seek_Entry( nPortionStart, &nInvPos ); 1955*cdf0e10cSrcweir DBG_ASSERT( bFound && ( nInvPos < (aPositions.Count()-1) ), "InvPos ?!" ); 1956*cdf0e10cSrcweir for ( sal_uInt16 i = nInvPos+1; i < aPositions.Count(); i++ ) 1957*cdf0e10cSrcweir { 1958*cdf0e10cSrcweir TETextPortion* pNew = new TETextPortion( (sal_uInt16)aPositions[i] - (sal_uInt16)aPositions[i-1] ); 1959*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().Insert( pNew, pTEParaPortion->GetTextPortions().Count()); 1960*cdf0e10cSrcweir } 1961*cdf0e10cSrcweir 1962*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "Keine Portions?!" ); 1963*cdf0e10cSrcweir #ifdef EDITDEBUG 1964*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->DbgCheckTextPortions(), "Portions kaputt?" ); 1965*cdf0e10cSrcweir #endif 1966*cdf0e10cSrcweir } 1967*cdf0e10cSrcweir 1968*cdf0e10cSrcweir void TextEngine::RecalcTextPortion( sal_uLong nPara, sal_uInt16 nStartPos, short nNewChars ) 1969*cdf0e10cSrcweir { 1970*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 1971*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "Keine Portions!" ); 1972*cdf0e10cSrcweir DBG_ASSERT( nNewChars, "RecalcTextPortion mit Diff == 0" ); 1973*cdf0e10cSrcweir 1974*cdf0e10cSrcweir TextNode* const pNode = pTEParaPortion->GetNode(); 1975*cdf0e10cSrcweir if ( nNewChars > 0 ) 1976*cdf0e10cSrcweir { 1977*cdf0e10cSrcweir // Wenn an nStartPos ein Attribut beginnt/endet, oder vor nStartPos 1978*cdf0e10cSrcweir // ein Tab steht, faengt eine neue Portion an, 1979*cdf0e10cSrcweir // ansonsten wird die Portion an nStartPos erweitert. 1980*cdf0e10cSrcweir // Oder wenn ganz vorne ( StartPos 0 ) und dann ein Tab 1981*cdf0e10cSrcweir 1982*cdf0e10cSrcweir if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) || 1983*cdf0e10cSrcweir ( nStartPos && ( pNode->GetText().GetChar( nStartPos - 1 ) == '\t' ) ) || 1984*cdf0e10cSrcweir ( ( !nStartPos && ( nNewChars < pNode->GetText().Len() ) && pNode->GetText().GetChar( nNewChars ) == '\t' ) ) ) 1985*cdf0e10cSrcweir { 1986*cdf0e10cSrcweir sal_uInt16 nNewPortionPos = 0; 1987*cdf0e10cSrcweir if ( nStartPos ) 1988*cdf0e10cSrcweir nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1; 1989*cdf0e10cSrcweir // else if ( ( pTEParaPortion->GetTextPortions().Count() == 1 ) && 1990*cdf0e10cSrcweir // !pTEParaPortion->GetTextPortions()[0]->GetLen() ) 1991*cdf0e10cSrcweir // pTEParaPortion->GetTextPortions().Reset(); // DummyPortion 1992*cdf0e10cSrcweir 1993*cdf0e10cSrcweir // Eine leere Portion kann hier stehen, wenn der Absatz leer war, 1994*cdf0e10cSrcweir // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist. 1995*cdf0e10cSrcweir if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().Count() ) && 1996*cdf0e10cSrcweir !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() ) 1997*cdf0e10cSrcweir { 1998*cdf0e10cSrcweir // Dann die leere Portion verwenden. 1999*cdf0e10cSrcweir sal_uInt16 & r = 2000*cdf0e10cSrcweir pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen(); 2001*cdf0e10cSrcweir r = r + nNewChars; 2002*cdf0e10cSrcweir } 2003*cdf0e10cSrcweir else 2004*cdf0e10cSrcweir { 2005*cdf0e10cSrcweir TETextPortion* pNewPortion = new TETextPortion( nNewChars ); 2006*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().Insert( pNewPortion, nNewPortionPos ); 2007*cdf0e10cSrcweir } 2008*cdf0e10cSrcweir } 2009*cdf0e10cSrcweir else 2010*cdf0e10cSrcweir { 2011*cdf0e10cSrcweir sal_uInt16 nPortionStart; 2012*cdf0e10cSrcweir const sal_uInt16 nTP = pTEParaPortion->GetTextPortions(). 2013*cdf0e10cSrcweir FindPortion( nStartPos, nPortionStart ); 2014*cdf0e10cSrcweir TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ]; 2015*cdf0e10cSrcweir DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); 2016*cdf0e10cSrcweir pTP->GetLen() = pTP->GetLen() + nNewChars; 2017*cdf0e10cSrcweir pTP->GetWidth() = (-1); 2018*cdf0e10cSrcweir } 2019*cdf0e10cSrcweir } 2020*cdf0e10cSrcweir else 2021*cdf0e10cSrcweir { 2022*cdf0e10cSrcweir // Portion schrumpfen oder ggf. entfernen. 2023*cdf0e10cSrcweir // Vor Aufruf dieser Methode muss sichergestellt sein, dass 2024*cdf0e10cSrcweir // keine Portions in dem geloeschten Bereich lagen! 2025*cdf0e10cSrcweir 2026*cdf0e10cSrcweir // Es darf keine reinragende oder im Bereich startende Portion geben, 2027*cdf0e10cSrcweir // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein 2028*cdf0e10cSrcweir sal_uInt16 nPortion = 0; 2029*cdf0e10cSrcweir sal_uInt16 nPos = 0; 2030*cdf0e10cSrcweir sal_uInt16 nEnd = nStartPos-nNewChars; 2031*cdf0e10cSrcweir sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().Count(); 2032*cdf0e10cSrcweir TETextPortion* pTP = 0; 2033*cdf0e10cSrcweir for ( nPortion = 0; nPortion < nPortions; nPortion++ ) 2034*cdf0e10cSrcweir { 2035*cdf0e10cSrcweir pTP = pTEParaPortion->GetTextPortions()[ nPortion ]; 2036*cdf0e10cSrcweir if ( ( nPos+pTP->GetLen() ) > nStartPos ) 2037*cdf0e10cSrcweir { 2038*cdf0e10cSrcweir DBG_ASSERT( nPos <= nStartPos, "Start falsch!" ); 2039*cdf0e10cSrcweir DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" ); 2040*cdf0e10cSrcweir break; 2041*cdf0e10cSrcweir } 2042*cdf0e10cSrcweir nPos = nPos + pTP->GetLen(); 2043*cdf0e10cSrcweir } 2044*cdf0e10cSrcweir DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); 2045*cdf0e10cSrcweir if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) ) 2046*cdf0e10cSrcweir { 2047*cdf0e10cSrcweir // Portion entfernen; 2048*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().Remove( nPortion ); 2049*cdf0e10cSrcweir delete pTP; 2050*cdf0e10cSrcweir } 2051*cdf0e10cSrcweir else 2052*cdf0e10cSrcweir { 2053*cdf0e10cSrcweir DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" ); 2054*cdf0e10cSrcweir pTP->GetLen() = pTP->GetLen() + nNewChars; 2055*cdf0e10cSrcweir } 2056*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "RecalcTextPortions: Keine mehr da!" ); 2057*cdf0e10cSrcweir } 2058*cdf0e10cSrcweir 2059*cdf0e10cSrcweir #ifdef EDITDEBUG 2060*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->DbgCheckTextPortions(), "Portions kaputt?" ); 2061*cdf0e10cSrcweir #endif 2062*cdf0e10cSrcweir } 2063*cdf0e10cSrcweir 2064*cdf0e10cSrcweir void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection ) 2065*cdf0e10cSrcweir { 2066*cdf0e10cSrcweir if ( !GetUpdateMode() ) 2067*cdf0e10cSrcweir return; 2068*cdf0e10cSrcweir 2069*cdf0e10cSrcweir if ( !IsFormatted() ) 2070*cdf0e10cSrcweir FormatDoc(); 2071*cdf0e10cSrcweir 2072*cdf0e10cSrcweir bool bTransparent = false; 2073*cdf0e10cSrcweir Window* pOutWin = dynamic_cast<Window*>(pOutDev); 2074*cdf0e10cSrcweir bTransparent = (pOutWin && pOutWin->IsPaintTransparent()); 2075*cdf0e10cSrcweir 2076*cdf0e10cSrcweir long nY = rStartPos.Y(); 2077*cdf0e10cSrcweir 2078*cdf0e10cSrcweir TextPaM const* pSelStart = 0; 2079*cdf0e10cSrcweir TextPaM const* pSelEnd = 0; 2080*cdf0e10cSrcweir if ( pSelection && pSelection->HasRange() ) 2081*cdf0e10cSrcweir { 2082*cdf0e10cSrcweir sal_Bool bInvers = pSelection->GetEnd() < pSelection->GetStart(); 2083*cdf0e10cSrcweir pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); 2084*cdf0e10cSrcweir pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); 2085*cdf0e10cSrcweir } 2086*cdf0e10cSrcweir DBG_ASSERT( !pPaintRange || ( pPaintRange->GetStart() < pPaintRange->GetEnd() ), "ImpPaint: Paint-Range?!" ); 2087*cdf0e10cSrcweir 2088*cdf0e10cSrcweir const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); 2089*cdf0e10cSrcweir 2090*cdf0e10cSrcweir // -------------------------------------------------- 2091*cdf0e10cSrcweir // Ueber alle Absaetze... 2092*cdf0e10cSrcweir // -------------------------------------------------- 2093*cdf0e10cSrcweir for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ ) 2094*cdf0e10cSrcweir { 2095*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); 2096*cdf0e10cSrcweir // falls beim Tippen Idle-Formatierung, asynchrones Paint. 2097*cdf0e10cSrcweir if ( pPortion->IsInvalid() ) 2098*cdf0e10cSrcweir return; 2099*cdf0e10cSrcweir 2100*cdf0e10cSrcweir sal_uLong nParaHeight = CalcParaHeight( nPara ); 2101*cdf0e10cSrcweir sal_uInt16 nIndex = 0; 2102*cdf0e10cSrcweir if ( ( !pPaintArea || ( ( nY + (long)nParaHeight ) > pPaintArea->Top() ) ) 2103*cdf0e10cSrcweir && ( !pPaintRange || ( ( nPara >= pPaintRange->GetStart().GetPara() ) && ( nPara <= pPaintRange->GetEnd().GetPara() ) ) ) ) 2104*cdf0e10cSrcweir { 2105*cdf0e10cSrcweir // -------------------------------------------------- 2106*cdf0e10cSrcweir // Ueber die Zeilen des Absatzes... 2107*cdf0e10cSrcweir // -------------------------------------------------- 2108*cdf0e10cSrcweir sal_uInt16 nLines = pPortion->GetLines().Count(); 2109*cdf0e10cSrcweir for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) 2110*cdf0e10cSrcweir { 2111*cdf0e10cSrcweir TextLine* pLine = pPortion->GetLines().GetObject(nLine); 2112*cdf0e10cSrcweir Point aTmpPos( rStartPos.X() + pLine->GetStartX(), nY ); 2113*cdf0e10cSrcweir 2114*cdf0e10cSrcweir if ( ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) ) 2115*cdf0e10cSrcweir && ( !pPaintRange || ( 2116*cdf0e10cSrcweir ( TextPaM( nPara, pLine->GetStart() ) < pPaintRange->GetEnd() ) && 2117*cdf0e10cSrcweir ( TextPaM( nPara, pLine->GetEnd() ) > pPaintRange->GetStart() ) ) ) ) 2118*cdf0e10cSrcweir { 2119*cdf0e10cSrcweir // -------------------------------------------------- 2120*cdf0e10cSrcweir // Ueber die Portions der Zeile... 2121*cdf0e10cSrcweir // -------------------------------------------------- 2122*cdf0e10cSrcweir nIndex = pLine->GetStart(); 2123*cdf0e10cSrcweir for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ ) 2124*cdf0e10cSrcweir { 2125*cdf0e10cSrcweir DBG_ASSERT( pPortion->GetTextPortions().Count(), "Zeile ohne Textportion im Paint!" ); 2126*cdf0e10cSrcweir TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( y ); 2127*cdf0e10cSrcweir DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" ); 2128*cdf0e10cSrcweir 2129*cdf0e10cSrcweir ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */); 2130*cdf0e10cSrcweir 2131*cdf0e10cSrcweir long nTxtWidth = pTextPortion->GetWidth(); 2132*cdf0e10cSrcweir aTmpPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nIndex, nIndex ); 2133*cdf0e10cSrcweir 2134*cdf0e10cSrcweir // nur ausgeben, was im sichtbaren Bereich beginnt: 2135*cdf0e10cSrcweir if ( ( ( aTmpPos.X() + nTxtWidth ) >= 0 ) 2136*cdf0e10cSrcweir && ( !pPaintRange || ( 2137*cdf0e10cSrcweir ( TextPaM( nPara, nIndex ) < pPaintRange->GetEnd() ) && 2138*cdf0e10cSrcweir ( TextPaM( nPara, nIndex + pTextPortion->GetLen() ) > pPaintRange->GetStart() ) ) ) ) 2139*cdf0e10cSrcweir { 2140*cdf0e10cSrcweir switch ( pTextPortion->GetKind() ) 2141*cdf0e10cSrcweir { 2142*cdf0e10cSrcweir case PORTIONKIND_TEXT: 2143*cdf0e10cSrcweir { 2144*cdf0e10cSrcweir { 2145*cdf0e10cSrcweir Font aFont; 2146*cdf0e10cSrcweir SeekCursor( nPara, nIndex+1, aFont, pOutDev ); 2147*cdf0e10cSrcweir if( bTransparent ) 2148*cdf0e10cSrcweir aFont.SetTransparent( sal_True ); 2149*cdf0e10cSrcweir else if ( pSelection ) 2150*cdf0e10cSrcweir aFont.SetTransparent( sal_False ); 2151*cdf0e10cSrcweir pOutDev->SetFont( aFont ); 2152*cdf0e10cSrcweir 2153*cdf0e10cSrcweir sal_uInt16 nTmpIndex = nIndex; 2154*cdf0e10cSrcweir sal_uInt16 nEnd = nTmpIndex + pTextPortion->GetLen(); 2155*cdf0e10cSrcweir Point aPos = aTmpPos; 2156*cdf0e10cSrcweir if ( pPaintRange ) 2157*cdf0e10cSrcweir { 2158*cdf0e10cSrcweir // evtl soll nicht alles ausgegeben werden... 2159*cdf0e10cSrcweir if ( ( pPaintRange->GetStart().GetPara() == nPara ) 2160*cdf0e10cSrcweir && ( nTmpIndex < pPaintRange->GetStart().GetIndex() ) ) 2161*cdf0e10cSrcweir { 2162*cdf0e10cSrcweir nTmpIndex = pPaintRange->GetStart().GetIndex(); 2163*cdf0e10cSrcweir } 2164*cdf0e10cSrcweir if ( ( pPaintRange->GetEnd().GetPara() == nPara ) 2165*cdf0e10cSrcweir && ( nEnd > pPaintRange->GetEnd().GetIndex() ) ) 2166*cdf0e10cSrcweir { 2167*cdf0e10cSrcweir nEnd = pPaintRange->GetEnd().GetIndex(); 2168*cdf0e10cSrcweir } 2169*cdf0e10cSrcweir } 2170*cdf0e10cSrcweir 2171*cdf0e10cSrcweir sal_Bool bDone = sal_False; 2172*cdf0e10cSrcweir if ( pSelStart ) 2173*cdf0e10cSrcweir { 2174*cdf0e10cSrcweir // liegt ein Teil in der Selektion??? 2175*cdf0e10cSrcweir TextPaM aTextStart( nPara, nTmpIndex ); 2176*cdf0e10cSrcweir TextPaM aTextEnd( nPara, nEnd ); 2177*cdf0e10cSrcweir if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) 2178*cdf0e10cSrcweir { 2179*cdf0e10cSrcweir sal_uInt16 nL; 2180*cdf0e10cSrcweir 2181*cdf0e10cSrcweir // 1) Bereich vor Selektion 2182*cdf0e10cSrcweir if ( aTextStart < *pSelStart ) 2183*cdf0e10cSrcweir { 2184*cdf0e10cSrcweir nL = pSelStart->GetIndex() - nTmpIndex; 2185*cdf0e10cSrcweir pOutDev->SetFont( aFont); 2186*cdf0e10cSrcweir aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); 2187*cdf0e10cSrcweir pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); 2188*cdf0e10cSrcweir nTmpIndex = nTmpIndex + nL; 2189*cdf0e10cSrcweir 2190*cdf0e10cSrcweir } 2191*cdf0e10cSrcweir // 2) Bereich mit Selektion 2192*cdf0e10cSrcweir nL = nEnd-nTmpIndex; 2193*cdf0e10cSrcweir if ( aTextEnd > *pSelEnd ) 2194*cdf0e10cSrcweir nL = pSelEnd->GetIndex() - nTmpIndex; 2195*cdf0e10cSrcweir if ( nL ) 2196*cdf0e10cSrcweir { 2197*cdf0e10cSrcweir Color aOldTextColor = pOutDev->GetTextColor(); 2198*cdf0e10cSrcweir pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() ); 2199*cdf0e10cSrcweir pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() ); 2200*cdf0e10cSrcweir aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); 2201*cdf0e10cSrcweir pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); 2202*cdf0e10cSrcweir pOutDev->SetTextColor( aOldTextColor ); 2203*cdf0e10cSrcweir pOutDev->SetTextFillColor(); 2204*cdf0e10cSrcweir nTmpIndex = nTmpIndex + nL; 2205*cdf0e10cSrcweir } 2206*cdf0e10cSrcweir 2207*cdf0e10cSrcweir // 3) Bereich nach Selektion 2208*cdf0e10cSrcweir if ( nTmpIndex < nEnd ) 2209*cdf0e10cSrcweir { 2210*cdf0e10cSrcweir nL = nEnd-nTmpIndex; 2211*cdf0e10cSrcweir aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); 2212*cdf0e10cSrcweir pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); 2213*cdf0e10cSrcweir } 2214*cdf0e10cSrcweir bDone = sal_True; 2215*cdf0e10cSrcweir } 2216*cdf0e10cSrcweir } 2217*cdf0e10cSrcweir if ( !bDone ) 2218*cdf0e10cSrcweir { 2219*cdf0e10cSrcweir aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nEnd ); 2220*cdf0e10cSrcweir pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); 2221*cdf0e10cSrcweir } 2222*cdf0e10cSrcweir } 2223*cdf0e10cSrcweir 2224*cdf0e10cSrcweir } 2225*cdf0e10cSrcweir break; 2226*cdf0e10cSrcweir case PORTIONKIND_TAB: 2227*cdf0e10cSrcweir { 2228*cdf0e10cSrcweir // Bei HideSelection() nur Range, pSelection = 0. 2229*cdf0e10cSrcweir if ( pSelStart || pPaintRange ) 2230*cdf0e10cSrcweir { 2231*cdf0e10cSrcweir Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) ); 2232*cdf0e10cSrcweir sal_Bool bDone = sal_False; 2233*cdf0e10cSrcweir if ( pSelStart ) 2234*cdf0e10cSrcweir { 2235*cdf0e10cSrcweir // liegt der Tab in der Selektion??? 2236*cdf0e10cSrcweir TextPaM aTextStart( nPara, nIndex ); 2237*cdf0e10cSrcweir TextPaM aTextEnd( nPara, nIndex+1 ); 2238*cdf0e10cSrcweir if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) 2239*cdf0e10cSrcweir { 2240*cdf0e10cSrcweir Color aOldColor = pOutDev->GetFillColor(); 2241*cdf0e10cSrcweir pOutDev->SetFillColor( rStyleSettings.GetHighlightColor() ); 2242*cdf0e10cSrcweir pOutDev->DrawRect( aTabArea ); 2243*cdf0e10cSrcweir pOutDev->SetFillColor( aOldColor ); 2244*cdf0e10cSrcweir bDone = sal_True; 2245*cdf0e10cSrcweir } 2246*cdf0e10cSrcweir } 2247*cdf0e10cSrcweir if ( !bDone ) 2248*cdf0e10cSrcweir { 2249*cdf0e10cSrcweir pOutDev->Erase( aTabArea ); 2250*cdf0e10cSrcweir } 2251*cdf0e10cSrcweir } 2252*cdf0e10cSrcweir #ifdef EDITDEBUG 2253*cdf0e10cSrcweir Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) ); 2254*cdf0e10cSrcweir Color aOldColor = pOutDev->GetFillColor(); 2255*cdf0e10cSrcweir pOutDev->SetFillColor( (y%2) ? COL_RED : COL_GREEN ); 2256*cdf0e10cSrcweir pOutDev->DrawRect( aTabArea ); 2257*cdf0e10cSrcweir pOutDev->SetFillColor( aOldColor ); 2258*cdf0e10cSrcweir #endif 2259*cdf0e10cSrcweir } 2260*cdf0e10cSrcweir break; 2261*cdf0e10cSrcweir default: DBG_ERROR( "ImpPaint: Unknown Portion-Type !" ); 2262*cdf0e10cSrcweir } 2263*cdf0e10cSrcweir } 2264*cdf0e10cSrcweir 2265*cdf0e10cSrcweir nIndex = nIndex + pTextPortion->GetLen(); 2266*cdf0e10cSrcweir } 2267*cdf0e10cSrcweir } 2268*cdf0e10cSrcweir 2269*cdf0e10cSrcweir nY += mnCharHeight; 2270*cdf0e10cSrcweir 2271*cdf0e10cSrcweir if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) ) 2272*cdf0e10cSrcweir break; // keine sichtbaren Aktionen mehr... 2273*cdf0e10cSrcweir } 2274*cdf0e10cSrcweir } 2275*cdf0e10cSrcweir else 2276*cdf0e10cSrcweir { 2277*cdf0e10cSrcweir nY += nParaHeight; 2278*cdf0e10cSrcweir } 2279*cdf0e10cSrcweir 2280*cdf0e10cSrcweir if ( pPaintArea && ( nY > pPaintArea->Bottom() ) ) 2281*cdf0e10cSrcweir break; // keine sichtbaren Aktionen mehr... 2282*cdf0e10cSrcweir } 2283*cdf0e10cSrcweir } 2284*cdf0e10cSrcweir 2285*cdf0e10cSrcweir sal_Bool TextEngine::CreateLines( sal_uLong nPara ) 2286*cdf0e10cSrcweir { 2287*cdf0e10cSrcweir // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False 2288*cdf0e10cSrcweir 2289*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 2290*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 2291*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" ); 2292*cdf0e10cSrcweir 2293*cdf0e10cSrcweir sal_uInt16 nOldLineCount = pTEParaPortion->GetLines().Count(); 2294*cdf0e10cSrcweir 2295*cdf0e10cSrcweir // --------------------------------------------------------------- 2296*cdf0e10cSrcweir // Schnelle Sonderbehandlung fuer leere Absaetze... 2297*cdf0e10cSrcweir // --------------------------------------------------------------- 2298*cdf0e10cSrcweir if ( pTEParaPortion->GetNode()->GetText().Len() == 0 ) 2299*cdf0e10cSrcweir { 2300*cdf0e10cSrcweir // schnelle Sonderbehandlung... 2301*cdf0e10cSrcweir if ( pTEParaPortion->GetTextPortions().Count() ) 2302*cdf0e10cSrcweir pTEParaPortion->GetTextPortions().Reset(); 2303*cdf0e10cSrcweir if ( pTEParaPortion->GetLines().Count() ) 2304*cdf0e10cSrcweir pTEParaPortion->GetLines().DeleteAndDestroy( 0, pTEParaPortion->GetLines().Count() ); 2305*cdf0e10cSrcweir CreateAndInsertEmptyLine( nPara ); 2306*cdf0e10cSrcweir pTEParaPortion->SetValid(); 2307*cdf0e10cSrcweir return nOldLineCount != pTEParaPortion->GetLines().Count(); 2308*cdf0e10cSrcweir } 2309*cdf0e10cSrcweir 2310*cdf0e10cSrcweir // --------------------------------------------------------------- 2311*cdf0e10cSrcweir // Initialisierung...... 2312*cdf0e10cSrcweir // --------------------------------------------------------------- 2313*cdf0e10cSrcweir 2314*cdf0e10cSrcweir if ( pTEParaPortion->GetLines().Count() == 0 ) 2315*cdf0e10cSrcweir { 2316*cdf0e10cSrcweir TextLine* pL = new TextLine; 2317*cdf0e10cSrcweir pTEParaPortion->GetLines().Insert( pL, 0 ); 2318*cdf0e10cSrcweir } 2319*cdf0e10cSrcweir 2320*cdf0e10cSrcweir const short nInvalidDiff = pTEParaPortion->GetInvalidDiff(); 2321*cdf0e10cSrcweir const sal_uInt16 nInvalidStart = pTEParaPortion->GetInvalidPosStart(); 2322*cdf0e10cSrcweir const sal_uInt16 nInvalidEnd = nInvalidStart + Abs( nInvalidDiff ); 2323*cdf0e10cSrcweir sal_Bool bQuickFormat = sal_False; 2324*cdf0e10cSrcweir 2325*cdf0e10cSrcweir if ( !pTEParaPortion->GetWritingDirectionInfos().Count() ) 2326*cdf0e10cSrcweir ImpInitWritingDirections( nPara ); 2327*cdf0e10cSrcweir 2328*cdf0e10cSrcweir if ( pTEParaPortion->GetWritingDirectionInfos().Count() == 1 ) 2329*cdf0e10cSrcweir { 2330*cdf0e10cSrcweir if ( pTEParaPortion->IsSimpleInvalid() && ( nInvalidDiff > 0 ) ) 2331*cdf0e10cSrcweir { 2332*cdf0e10cSrcweir bQuickFormat = sal_True; 2333*cdf0e10cSrcweir } 2334*cdf0e10cSrcweir else if ( ( pTEParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) ) 2335*cdf0e10cSrcweir { 2336*cdf0e10cSrcweir // pruefen, ob loeschen ueber Portiongrenzen erfolgte... 2337*cdf0e10cSrcweir sal_uInt16 nStart = nInvalidStart; // DOPPELT !!!!!!!!!!!!!!! 2338*cdf0e10cSrcweir sal_uInt16 nEnd = nStart - nInvalidDiff; // neg. 2339*cdf0e10cSrcweir bQuickFormat = sal_True; 2340*cdf0e10cSrcweir sal_uInt16 nPos = 0; 2341*cdf0e10cSrcweir sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().Count(); 2342*cdf0e10cSrcweir for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ ) 2343*cdf0e10cSrcweir { 2344*cdf0e10cSrcweir // Es darf kein Start/Ende im geloeschten Bereich liegen. 2345*cdf0e10cSrcweir TETextPortion* const pTP = pTEParaPortion->GetTextPortions().GetObject( nTP ); 2346*cdf0e10cSrcweir nPos = nPos + pTP->GetLen(); 2347*cdf0e10cSrcweir if ( ( nPos > nStart ) && ( nPos < nEnd ) ) 2348*cdf0e10cSrcweir { 2349*cdf0e10cSrcweir bQuickFormat = sal_False; 2350*cdf0e10cSrcweir break; 2351*cdf0e10cSrcweir } 2352*cdf0e10cSrcweir } 2353*cdf0e10cSrcweir } 2354*cdf0e10cSrcweir } 2355*cdf0e10cSrcweir 2356*cdf0e10cSrcweir if ( bQuickFormat ) 2357*cdf0e10cSrcweir RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff ); 2358*cdf0e10cSrcweir else 2359*cdf0e10cSrcweir CreateTextPortions( nPara, nInvalidStart ); 2360*cdf0e10cSrcweir 2361*cdf0e10cSrcweir // --------------------------------------------------------------- 2362*cdf0e10cSrcweir // Zeile mit InvalidPos suchen, eine Zeile davor beginnen... 2363*cdf0e10cSrcweir // Zeilen flaggen => nicht removen ! 2364*cdf0e10cSrcweir // --------------------------------------------------------------- 2365*cdf0e10cSrcweir 2366*cdf0e10cSrcweir sal_uInt16 nLine = pTEParaPortion->GetLines().Count()-1; 2367*cdf0e10cSrcweir for ( sal_uInt16 nL = 0; nL <= nLine; nL++ ) 2368*cdf0e10cSrcweir { 2369*cdf0e10cSrcweir TextLine* pLine = pTEParaPortion->GetLines().GetObject( nL ); 2370*cdf0e10cSrcweir if ( pLine->GetEnd() > nInvalidStart ) 2371*cdf0e10cSrcweir { 2372*cdf0e10cSrcweir nLine = nL; 2373*cdf0e10cSrcweir break; 2374*cdf0e10cSrcweir } 2375*cdf0e10cSrcweir pLine->SetValid(); 2376*cdf0e10cSrcweir } 2377*cdf0e10cSrcweir // Eine Zeile davor beginnen... 2378*cdf0e10cSrcweir // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern. 2379*cdf0e10cSrcweir if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().Len() ) || ( nInvalidDiff <= 0 ) ) ) 2380*cdf0e10cSrcweir nLine--; 2381*cdf0e10cSrcweir 2382*cdf0e10cSrcweir TextLine* pLine = pTEParaPortion->GetLines().GetObject( nLine ); 2383*cdf0e10cSrcweir 2384*cdf0e10cSrcweir // --------------------------------------------------------------- 2385*cdf0e10cSrcweir // Ab hier alle Zeilen durchformatieren... 2386*cdf0e10cSrcweir // --------------------------------------------------------------- 2387*cdf0e10cSrcweir sal_uInt16 nDelFromLine = 0xFFFF; 2388*cdf0e10cSrcweir sal_Bool bLineBreak = sal_False; 2389*cdf0e10cSrcweir 2390*cdf0e10cSrcweir sal_uInt16 nIndex = pLine->GetStart(); 2391*cdf0e10cSrcweir TextLine aSaveLine( *pLine ); 2392*cdf0e10cSrcweir 2393*cdf0e10cSrcweir Font aFont; 2394*cdf0e10cSrcweir 2395*cdf0e10cSrcweir sal_Bool bCalcPortion = sal_True; 2396*cdf0e10cSrcweir 2397*cdf0e10cSrcweir while ( nIndex < pNode->GetText().Len() ) 2398*cdf0e10cSrcweir { 2399*cdf0e10cSrcweir sal_Bool bEOL = sal_False; 2400*cdf0e10cSrcweir sal_Bool bEOC = sal_False; 2401*cdf0e10cSrcweir sal_uInt16 nPortionStart = 0; 2402*cdf0e10cSrcweir sal_uInt16 nPortionEnd = 0; 2403*cdf0e10cSrcweir 2404*cdf0e10cSrcweir sal_uInt16 nTmpPos = nIndex; 2405*cdf0e10cSrcweir sal_uInt16 nTmpPortion = pLine->GetStartPortion(); 2406*cdf0e10cSrcweir long nTmpWidth = mpDoc->GetLeftMargin(); 2407*cdf0e10cSrcweir // long nXWidth = mnMaxTextWidth ? ( mnMaxTextWidth - mpDoc->GetLeftMargin() ) : 0x7FFFFFFF; 2408*cdf0e10cSrcweir // Margin nicht abziehen, ist schon in TmpWidth enthalten. 2409*cdf0e10cSrcweir long nXWidth = mnMaxTextWidth ? mnMaxTextWidth : 0x7FFFFFFF; 2410*cdf0e10cSrcweir if ( nXWidth < nTmpWidth ) 2411*cdf0e10cSrcweir nXWidth = nTmpWidth; 2412*cdf0e10cSrcweir 2413*cdf0e10cSrcweir // Portion suchen, die nicht mehr in Zeile passt.... 2414*cdf0e10cSrcweir TETextPortion* pPortion = 0; 2415*cdf0e10cSrcweir sal_Bool bBrokenLine = sal_False; 2416*cdf0e10cSrcweir bLineBreak = sal_False; 2417*cdf0e10cSrcweir 2418*cdf0e10cSrcweir while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().Count() ) ) 2419*cdf0e10cSrcweir { 2420*cdf0e10cSrcweir nPortionStart = nTmpPos; 2421*cdf0e10cSrcweir pPortion = pTEParaPortion->GetTextPortions().GetObject( nTmpPortion ); 2422*cdf0e10cSrcweir DBG_ASSERT( pPortion->GetLen(), "Leere Portion in CreateLines ?!" ); 2423*cdf0e10cSrcweir if ( pNode->GetText().GetChar( nTmpPos ) == '\t' ) 2424*cdf0e10cSrcweir { 2425*cdf0e10cSrcweir long nCurPos = nTmpWidth-mpDoc->GetLeftMargin(); 2426*cdf0e10cSrcweir nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin(); 2427*cdf0e10cSrcweir pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin(); 2428*cdf0e10cSrcweir // Wenn dies das erste Token in der Zeile ist, und 2429*cdf0e10cSrcweir // nTmpWidth > aPaperSize.Width, habe ich eine Endlos-Schleife! 2430*cdf0e10cSrcweir if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) 2431*cdf0e10cSrcweir { 2432*cdf0e10cSrcweir // Aber was jetzt ? Tab passend machen! 2433*cdf0e10cSrcweir pPortion->GetWidth() = nXWidth-1; 2434*cdf0e10cSrcweir nTmpWidth = pPortion->GetWidth(); 2435*cdf0e10cSrcweir bEOL = sal_True; 2436*cdf0e10cSrcweir bBrokenLine = sal_True; 2437*cdf0e10cSrcweir } 2438*cdf0e10cSrcweir pPortion->GetKind() = PORTIONKIND_TAB; 2439*cdf0e10cSrcweir } 2440*cdf0e10cSrcweir else 2441*cdf0e10cSrcweir { 2442*cdf0e10cSrcweir 2443*cdf0e10cSrcweir if ( bCalcPortion || !pPortion->HasValidSize() ) 2444*cdf0e10cSrcweir pPortion->GetWidth() = (long)CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() ); 2445*cdf0e10cSrcweir nTmpWidth += pPortion->GetWidth(); 2446*cdf0e10cSrcweir 2447*cdf0e10cSrcweir pPortion->GetRightToLeft() = ImpGetRightToLeft( nPara, nTmpPos+1 ); 2448*cdf0e10cSrcweir pPortion->GetKind() = PORTIONKIND_TEXT; 2449*cdf0e10cSrcweir } 2450*cdf0e10cSrcweir 2451*cdf0e10cSrcweir nTmpPos = nTmpPos + pPortion->GetLen(); 2452*cdf0e10cSrcweir nPortionEnd = nTmpPos; 2453*cdf0e10cSrcweir nTmpPortion++; 2454*cdf0e10cSrcweir } 2455*cdf0e10cSrcweir 2456*cdf0e10cSrcweir // das war evtl. eine Portion zu weit: 2457*cdf0e10cSrcweir sal_Bool bFixedEnd = sal_False; 2458*cdf0e10cSrcweir if ( nTmpWidth > nXWidth ) 2459*cdf0e10cSrcweir { 2460*cdf0e10cSrcweir nPortionEnd = nTmpPos; 2461*cdf0e10cSrcweir nTmpPos = nTmpPos - pPortion->GetLen(); 2462*cdf0e10cSrcweir nPortionStart = nTmpPos; 2463*cdf0e10cSrcweir nTmpPortion--; 2464*cdf0e10cSrcweir bEOL = sal_False; 2465*cdf0e10cSrcweir bEOC = sal_False; 2466*cdf0e10cSrcweir 2467*cdf0e10cSrcweir nTmpWidth -= pPortion->GetWidth(); 2468*cdf0e10cSrcweir if ( pPortion->GetKind() == PORTIONKIND_TAB ) 2469*cdf0e10cSrcweir { 2470*cdf0e10cSrcweir bEOL = sal_True; 2471*cdf0e10cSrcweir bFixedEnd = sal_True; 2472*cdf0e10cSrcweir } 2473*cdf0e10cSrcweir } 2474*cdf0e10cSrcweir else 2475*cdf0e10cSrcweir { 2476*cdf0e10cSrcweir bEOL = sal_True; 2477*cdf0e10cSrcweir bEOC = sal_True; 2478*cdf0e10cSrcweir pLine->SetEnd( nPortionEnd ); 2479*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "Keine TextPortions?" ); 2480*cdf0e10cSrcweir pLine->SetEndPortion( (sal_uInt16)pTEParaPortion->GetTextPortions().Count() - 1 ); 2481*cdf0e10cSrcweir } 2482*cdf0e10cSrcweir 2483*cdf0e10cSrcweir if ( bFixedEnd ) 2484*cdf0e10cSrcweir { 2485*cdf0e10cSrcweir pLine->SetEnd( nPortionStart ); 2486*cdf0e10cSrcweir pLine->SetEndPortion( nTmpPortion-1 ); 2487*cdf0e10cSrcweir } 2488*cdf0e10cSrcweir else if ( bLineBreak || bBrokenLine ) 2489*cdf0e10cSrcweir { 2490*cdf0e10cSrcweir pLine->SetEnd( nPortionStart+1 ); 2491*cdf0e10cSrcweir pLine->SetEndPortion( nTmpPortion-1 ); 2492*cdf0e10cSrcweir bEOC = sal_False; // wurde oben gesetzt, vielleich mal die if's umstellen? 2493*cdf0e10cSrcweir } 2494*cdf0e10cSrcweir else if ( !bEOL ) 2495*cdf0e10cSrcweir { 2496*cdf0e10cSrcweir DBG_ASSERT( (nPortionEnd-nPortionStart) == pPortion->GetLen(), "Doch eine andere Portion?!" ); 2497*cdf0e10cSrcweir long nRemainingWidth = mnMaxTextWidth - nTmpWidth; 2498*cdf0e10cSrcweir ImpBreakLine( nPara, pLine, pPortion, nPortionStart, nRemainingWidth ); 2499*cdf0e10cSrcweir } 2500*cdf0e10cSrcweir 2501*cdf0e10cSrcweir if ( ( ImpGetAlign() == TXTALIGN_CENTER ) || ( ImpGetAlign() == TXTALIGN_RIGHT ) ) 2502*cdf0e10cSrcweir { 2503*cdf0e10cSrcweir // Ausrichten... 2504*cdf0e10cSrcweir long nTextWidth = 0; 2505*cdf0e10cSrcweir for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) 2506*cdf0e10cSrcweir { 2507*cdf0e10cSrcweir TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions().GetObject( nTP ); 2508*cdf0e10cSrcweir nTextWidth += pTextPortion->GetWidth(); 2509*cdf0e10cSrcweir } 2510*cdf0e10cSrcweir long nSpace = mnMaxTextWidth - nTextWidth; 2511*cdf0e10cSrcweir if ( nSpace > 0 ) 2512*cdf0e10cSrcweir { 2513*cdf0e10cSrcweir if ( ImpGetAlign() == TXTALIGN_CENTER ) 2514*cdf0e10cSrcweir pLine->SetStartX( (sal_uInt16)(nSpace / 2) ); 2515*cdf0e10cSrcweir else // TXTALIGN_RIGHT 2516*cdf0e10cSrcweir pLine->SetStartX( (sal_uInt16)nSpace ); 2517*cdf0e10cSrcweir } 2518*cdf0e10cSrcweir } 2519*cdf0e10cSrcweir else 2520*cdf0e10cSrcweir { 2521*cdf0e10cSrcweir pLine->SetStartX( mpDoc->GetLeftMargin() ); 2522*cdf0e10cSrcweir } 2523*cdf0e10cSrcweir 2524*cdf0e10cSrcweir // ----------------------------------------------------------------- 2525*cdf0e10cSrcweir // pruefen, ob die Zeile neu ausgegeben werden muss... 2526*cdf0e10cSrcweir // ----------------------------------------------------------------- 2527*cdf0e10cSrcweir pLine->SetInvalid(); 2528*cdf0e10cSrcweir 2529*cdf0e10cSrcweir if ( pTEParaPortion->IsSimpleInvalid() ) 2530*cdf0e10cSrcweir { 2531*cdf0e10cSrcweir // Aenderung durch einfache Textaenderung... 2532*cdf0e10cSrcweir // Formatierung nicht abbrechen, da Portions evtl. wieder 2533*cdf0e10cSrcweir // gesplittet werden muessen! 2534*cdf0e10cSrcweir // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren! 2535*cdf0e10cSrcweir // Aber ggf. als Valid markieren, damit weniger Ausgabe... 2536*cdf0e10cSrcweir if ( pLine->GetEnd() < nInvalidStart ) 2537*cdf0e10cSrcweir { 2538*cdf0e10cSrcweir if ( *pLine == aSaveLine ) 2539*cdf0e10cSrcweir { 2540*cdf0e10cSrcweir pLine->SetValid(); 2541*cdf0e10cSrcweir } 2542*cdf0e10cSrcweir } 2543*cdf0e10cSrcweir else 2544*cdf0e10cSrcweir { 2545*cdf0e10cSrcweir sal_uInt16 nStart = pLine->GetStart(); 2546*cdf0e10cSrcweir sal_uInt16 nEnd = pLine->GetEnd(); 2547*cdf0e10cSrcweir 2548*cdf0e10cSrcweir if ( nStart > nInvalidEnd ) 2549*cdf0e10cSrcweir { 2550*cdf0e10cSrcweir if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) && 2551*cdf0e10cSrcweir ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) ) 2552*cdf0e10cSrcweir { 2553*cdf0e10cSrcweir pLine->SetValid(); 2554*cdf0e10cSrcweir if ( bCalcPortion && bQuickFormat ) 2555*cdf0e10cSrcweir { 2556*cdf0e10cSrcweir bCalcPortion = sal_False; 2557*cdf0e10cSrcweir pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); 2558*cdf0e10cSrcweir break; 2559*cdf0e10cSrcweir } 2560*cdf0e10cSrcweir } 2561*cdf0e10cSrcweir } 2562*cdf0e10cSrcweir else if ( bQuickFormat && ( nEnd > nInvalidEnd) ) 2563*cdf0e10cSrcweir { 2564*cdf0e10cSrcweir // Wenn die ungueltige Zeile so endet, dass die naechste an 2565*cdf0e10cSrcweir // der 'gleichen' Textstelle wie vorher beginnt, also nicht 2566*cdf0e10cSrcweir // anders umgebrochen wird, brauche ich dort auch nicht die 2567*cdf0e10cSrcweir // textbreiten neu bestimmen: 2568*cdf0e10cSrcweir if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) ) 2569*cdf0e10cSrcweir { 2570*cdf0e10cSrcweir bCalcPortion = sal_False; 2571*cdf0e10cSrcweir pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); 2572*cdf0e10cSrcweir break; 2573*cdf0e10cSrcweir } 2574*cdf0e10cSrcweir } 2575*cdf0e10cSrcweir } 2576*cdf0e10cSrcweir } 2577*cdf0e10cSrcweir 2578*cdf0e10cSrcweir nIndex = pLine->GetEnd(); // naechste Zeile Start = letzte Zeile Ende 2579*cdf0e10cSrcweir // weil nEnd hinter das letzte Zeichen zeigt! 2580*cdf0e10cSrcweir 2581*cdf0e10cSrcweir sal_uInt16 nEndPortion = pLine->GetEndPortion(); 2582*cdf0e10cSrcweir 2583*cdf0e10cSrcweir // Naechste Zeile oder ggf. neue Zeile.... 2584*cdf0e10cSrcweir pLine = 0; 2585*cdf0e10cSrcweir if ( nLine < pTEParaPortion->GetLines().Count()-1 ) 2586*cdf0e10cSrcweir pLine = pTEParaPortion->GetLines().GetObject( ++nLine ); 2587*cdf0e10cSrcweir if ( pLine && ( nIndex >= pNode->GetText().Len() ) ) 2588*cdf0e10cSrcweir { 2589*cdf0e10cSrcweir nDelFromLine = nLine; 2590*cdf0e10cSrcweir break; 2591*cdf0e10cSrcweir } 2592*cdf0e10cSrcweir if ( !pLine && ( nIndex < pNode->GetText().Len() ) ) 2593*cdf0e10cSrcweir { 2594*cdf0e10cSrcweir pLine = new TextLine; 2595*cdf0e10cSrcweir pTEParaPortion->GetLines().Insert( pLine, ++nLine ); 2596*cdf0e10cSrcweir } 2597*cdf0e10cSrcweir if ( pLine ) 2598*cdf0e10cSrcweir { 2599*cdf0e10cSrcweir aSaveLine = *pLine; 2600*cdf0e10cSrcweir pLine->SetStart( nIndex ); 2601*cdf0e10cSrcweir pLine->SetEnd( nIndex ); 2602*cdf0e10cSrcweir pLine->SetStartPortion( nEndPortion+1 ); 2603*cdf0e10cSrcweir pLine->SetEndPortion( nEndPortion+1 ); 2604*cdf0e10cSrcweir } 2605*cdf0e10cSrcweir } // while ( Index < Len ) 2606*cdf0e10cSrcweir 2607*cdf0e10cSrcweir if ( nDelFromLine != 0xFFFF ) 2608*cdf0e10cSrcweir pTEParaPortion->GetLines().DeleteAndDestroy( nDelFromLine, pTEParaPortion->GetLines().Count() - nDelFromLine ); 2609*cdf0e10cSrcweir 2610*cdf0e10cSrcweir DBG_ASSERT( pTEParaPortion->GetLines().Count(), "Keine Zeile nach CreateLines!" ); 2611*cdf0e10cSrcweir 2612*cdf0e10cSrcweir if ( bLineBreak == sal_True ) 2613*cdf0e10cSrcweir CreateAndInsertEmptyLine( nPara ); 2614*cdf0e10cSrcweir 2615*cdf0e10cSrcweir pTEParaPortion->SetValid(); 2616*cdf0e10cSrcweir 2617*cdf0e10cSrcweir return nOldLineCount != pTEParaPortion->GetLines().Count(); 2618*cdf0e10cSrcweir } 2619*cdf0e10cSrcweir 2620*cdf0e10cSrcweir String TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord ) 2621*cdf0e10cSrcweir { 2622*cdf0e10cSrcweir String aWord; 2623*cdf0e10cSrcweir if ( rCursorPos.GetPara() < mpDoc->GetNodes().Count() ) 2624*cdf0e10cSrcweir { 2625*cdf0e10cSrcweir TextSelection aSel( rCursorPos ); 2626*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( rCursorPos.GetPara() ); 2627*cdf0e10cSrcweir uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); 2628*cdf0e10cSrcweir i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); 2629*cdf0e10cSrcweir aSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos; 2630*cdf0e10cSrcweir aSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos; 2631*cdf0e10cSrcweir aWord = pNode->GetText().Copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() ); 2632*cdf0e10cSrcweir if ( pStartOfWord ) 2633*cdf0e10cSrcweir *pStartOfWord = aSel.GetStart(); 2634*cdf0e10cSrcweir } 2635*cdf0e10cSrcweir return aWord; 2636*cdf0e10cSrcweir } 2637*cdf0e10cSrcweir 2638*cdf0e10cSrcweir sal_Bool TextEngine::Read( SvStream& rInput, const TextSelection* pSel ) 2639*cdf0e10cSrcweir { 2640*cdf0e10cSrcweir sal_Bool bUpdate = GetUpdateMode(); 2641*cdf0e10cSrcweir SetUpdateMode( sal_False ); 2642*cdf0e10cSrcweir 2643*cdf0e10cSrcweir UndoActionStart(); 2644*cdf0e10cSrcweir TextSelection aSel; 2645*cdf0e10cSrcweir if ( pSel ) 2646*cdf0e10cSrcweir aSel = *pSel; 2647*cdf0e10cSrcweir else 2648*cdf0e10cSrcweir { 2649*cdf0e10cSrcweir sal_uLong nParas = mpDoc->GetNodes().Count(); 2650*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 ); 2651*cdf0e10cSrcweir aSel = TextPaM( nParas-1 , pNode->GetText().Len() ); 2652*cdf0e10cSrcweir } 2653*cdf0e10cSrcweir 2654*cdf0e10cSrcweir if ( aSel.HasRange() ) 2655*cdf0e10cSrcweir aSel = ImpDeleteText( aSel ); 2656*cdf0e10cSrcweir 2657*cdf0e10cSrcweir ByteString aLine; 2658*cdf0e10cSrcweir sal_Bool bDone = rInput.ReadLine( aLine ); 2659*cdf0e10cSrcweir String aTmpStr( aLine, rInput.GetStreamCharSet() ), aStr; 2660*cdf0e10cSrcweir while ( bDone ) 2661*cdf0e10cSrcweir { 2662*cdf0e10cSrcweir aSel = ImpInsertText( aSel, aTmpStr ); 2663*cdf0e10cSrcweir bDone = rInput.ReadLine( aLine ); 2664*cdf0e10cSrcweir aTmpStr = String( aLine, rInput.GetStreamCharSet() ); 2665*cdf0e10cSrcweir if ( bDone ) 2666*cdf0e10cSrcweir aSel = ImpInsertParaBreak( aSel.GetEnd() ); 2667*cdf0e10cSrcweir } 2668*cdf0e10cSrcweir 2669*cdf0e10cSrcweir UndoActionEnd(); 2670*cdf0e10cSrcweir 2671*cdf0e10cSrcweir TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() ); 2672*cdf0e10cSrcweir 2673*cdf0e10cSrcweir // Damit bei FormatAndUpdate nicht auf die ungueltige Selektion zugegriffen wird. 2674*cdf0e10cSrcweir if ( GetActiveView() ) 2675*cdf0e10cSrcweir GetActiveView()->ImpSetSelection( aNewSel ); 2676*cdf0e10cSrcweir 2677*cdf0e10cSrcweir SetUpdateMode( bUpdate ); 2678*cdf0e10cSrcweir FormatAndUpdate( GetActiveView() ); 2679*cdf0e10cSrcweir 2680*cdf0e10cSrcweir return rInput.GetError() ? sal_False : sal_True; 2681*cdf0e10cSrcweir } 2682*cdf0e10cSrcweir 2683*cdf0e10cSrcweir sal_Bool TextEngine::Write( SvStream& rOutput, const TextSelection* pSel, sal_Bool bHTML ) 2684*cdf0e10cSrcweir { 2685*cdf0e10cSrcweir TextSelection aSel; 2686*cdf0e10cSrcweir if ( pSel ) 2687*cdf0e10cSrcweir aSel = *pSel; 2688*cdf0e10cSrcweir else 2689*cdf0e10cSrcweir { 2690*cdf0e10cSrcweir sal_uLong nParas = mpDoc->GetNodes().Count(); 2691*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 ); 2692*cdf0e10cSrcweir aSel.GetStart() = TextPaM( 0, 0 ); 2693*cdf0e10cSrcweir aSel.GetEnd() = TextPaM( nParas-1, pNode->GetText().Len() ); 2694*cdf0e10cSrcweir } 2695*cdf0e10cSrcweir 2696*cdf0e10cSrcweir if ( bHTML ) 2697*cdf0e10cSrcweir { 2698*cdf0e10cSrcweir rOutput.WriteLine( "<HTML>" ); 2699*cdf0e10cSrcweir rOutput.WriteLine( "<BODY>" ); 2700*cdf0e10cSrcweir } 2701*cdf0e10cSrcweir 2702*cdf0e10cSrcweir for ( sal_uLong nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); nPara++ ) 2703*cdf0e10cSrcweir { 2704*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 2705*cdf0e10cSrcweir 2706*cdf0e10cSrcweir sal_uInt16 nStartPos = 0; 2707*cdf0e10cSrcweir sal_uInt16 nEndPos = pNode->GetText().Len(); 2708*cdf0e10cSrcweir if ( nPara == aSel.GetStart().GetPara() ) 2709*cdf0e10cSrcweir nStartPos = aSel.GetStart().GetIndex(); 2710*cdf0e10cSrcweir if ( nPara == aSel.GetEnd().GetPara() ) 2711*cdf0e10cSrcweir nEndPos = aSel.GetEnd().GetIndex(); 2712*cdf0e10cSrcweir 2713*cdf0e10cSrcweir String aText; 2714*cdf0e10cSrcweir if ( !bHTML ) 2715*cdf0e10cSrcweir { 2716*cdf0e10cSrcweir aText = pNode->GetText().Copy( nStartPos, nEndPos-nStartPos ); 2717*cdf0e10cSrcweir } 2718*cdf0e10cSrcweir else 2719*cdf0e10cSrcweir { 2720*cdf0e10cSrcweir aText.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "<P STYLE=\"margin-bottom: 0cm\">" ) ); 2721*cdf0e10cSrcweir 2722*cdf0e10cSrcweir if ( nStartPos == nEndPos ) 2723*cdf0e10cSrcweir { 2724*cdf0e10cSrcweir // Leerzeilen werden von Writer wegoptimiert 2725*cdf0e10cSrcweir aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "<BR>" ) ); 2726*cdf0e10cSrcweir } 2727*cdf0e10cSrcweir else 2728*cdf0e10cSrcweir { 2729*cdf0e10cSrcweir sal_uInt16 nTmpStart = nStartPos; 2730*cdf0e10cSrcweir sal_uInt16 nTmpEnd = nEndPos; 2731*cdf0e10cSrcweir do 2732*cdf0e10cSrcweir { 2733*cdf0e10cSrcweir TextCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( TEXTATTR_HYPERLINK, nTmpStart, nEndPos ); 2734*cdf0e10cSrcweir nTmpEnd = pAttr ? pAttr->GetStart() : nEndPos; 2735*cdf0e10cSrcweir 2736*cdf0e10cSrcweir // Text vor dem Attribut 2737*cdf0e10cSrcweir aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart ); 2738*cdf0e10cSrcweir 2739*cdf0e10cSrcweir if ( pAttr ) 2740*cdf0e10cSrcweir { 2741*cdf0e10cSrcweir nTmpEnd = Min( pAttr->GetEnd(), nEndPos ); 2742*cdf0e10cSrcweir 2743*cdf0e10cSrcweir // z.B. <A HREF="http://www.mopo.de/">Morgenpost</A> 2744*cdf0e10cSrcweir aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "<A HREF=\"" ) ); 2745*cdf0e10cSrcweir aText += ((const TextAttribHyperLink&) pAttr->GetAttr() ).GetURL(); 2746*cdf0e10cSrcweir aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "\">" ) ); 2747*cdf0e10cSrcweir nTmpStart = pAttr->GetStart(); 2748*cdf0e10cSrcweir aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart ); 2749*cdf0e10cSrcweir aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "</A>" ) ); 2750*cdf0e10cSrcweir 2751*cdf0e10cSrcweir nTmpStart = pAttr->GetEnd(); 2752*cdf0e10cSrcweir } 2753*cdf0e10cSrcweir } while ( nTmpEnd < nEndPos ); 2754*cdf0e10cSrcweir } 2755*cdf0e10cSrcweir 2756*cdf0e10cSrcweir aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "</P>" ) ); 2757*cdf0e10cSrcweir } 2758*cdf0e10cSrcweir rOutput.WriteLine( ByteString( aText, rOutput.GetStreamCharSet() ) ); 2759*cdf0e10cSrcweir } 2760*cdf0e10cSrcweir 2761*cdf0e10cSrcweir if ( bHTML ) 2762*cdf0e10cSrcweir { 2763*cdf0e10cSrcweir rOutput.WriteLine( "</BODY>" ); 2764*cdf0e10cSrcweir rOutput.WriteLine( "</HTML>" ); 2765*cdf0e10cSrcweir } 2766*cdf0e10cSrcweir 2767*cdf0e10cSrcweir return rOutput.GetError() ? sal_False : sal_True; 2768*cdf0e10cSrcweir } 2769*cdf0e10cSrcweir 2770*cdf0e10cSrcweir void TextEngine::RemoveAttribs( sal_uLong nPara, sal_Bool bIdleFormatAndUpdate ) 2771*cdf0e10cSrcweir { 2772*cdf0e10cSrcweir if ( nPara < mpDoc->GetNodes().Count() ) 2773*cdf0e10cSrcweir { 2774*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 2775*cdf0e10cSrcweir if ( pNode->GetCharAttribs().Count() ) 2776*cdf0e10cSrcweir { 2777*cdf0e10cSrcweir pNode->GetCharAttribs().Clear( sal_True ); 2778*cdf0e10cSrcweir 2779*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 2780*cdf0e10cSrcweir pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); 2781*cdf0e10cSrcweir 2782*cdf0e10cSrcweir mbFormatted = sal_False; 2783*cdf0e10cSrcweir 2784*cdf0e10cSrcweir if ( bIdleFormatAndUpdate ) 2785*cdf0e10cSrcweir IdleFormatAndUpdate( NULL, 0xFFFF ); 2786*cdf0e10cSrcweir else 2787*cdf0e10cSrcweir FormatAndUpdate( NULL ); 2788*cdf0e10cSrcweir } 2789*cdf0e10cSrcweir } 2790*cdf0e10cSrcweir } 2791*cdf0e10cSrcweir void TextEngine::RemoveAttribs( sal_uLong nPara, sal_uInt16 nWhich, sal_Bool bIdleFormatAndUpdate ) 2792*cdf0e10cSrcweir { 2793*cdf0e10cSrcweir if ( nPara < mpDoc->GetNodes().Count() ) 2794*cdf0e10cSrcweir { 2795*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 2796*cdf0e10cSrcweir if ( pNode->GetCharAttribs().Count() ) 2797*cdf0e10cSrcweir { 2798*cdf0e10cSrcweir TextCharAttribList& rAttribs = pNode->GetCharAttribs(); 2799*cdf0e10cSrcweir sal_uInt16 nAttrCount = rAttribs.Count(); 2800*cdf0e10cSrcweir for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr) 2801*cdf0e10cSrcweir { 2802*cdf0e10cSrcweir if(rAttribs.GetAttrib( nAttr - 1 )->Which() == nWhich) 2803*cdf0e10cSrcweir rAttribs.RemoveAttrib( nAttr -1 ); 2804*cdf0e10cSrcweir } 2805*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 2806*cdf0e10cSrcweir pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); 2807*cdf0e10cSrcweir mbFormatted = sal_False; 2808*cdf0e10cSrcweir if(bIdleFormatAndUpdate) 2809*cdf0e10cSrcweir IdleFormatAndUpdate( NULL, 0xFFFF ); 2810*cdf0e10cSrcweir else 2811*cdf0e10cSrcweir FormatAndUpdate( NULL ); 2812*cdf0e10cSrcweir } 2813*cdf0e10cSrcweir } 2814*cdf0e10cSrcweir } 2815*cdf0e10cSrcweir void TextEngine::RemoveAttrib( sal_uLong nPara, const TextCharAttrib& rAttrib ) 2816*cdf0e10cSrcweir { 2817*cdf0e10cSrcweir if ( nPara < mpDoc->GetNodes().Count() ) 2818*cdf0e10cSrcweir { 2819*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 2820*cdf0e10cSrcweir if ( pNode->GetCharAttribs().Count() ) 2821*cdf0e10cSrcweir { 2822*cdf0e10cSrcweir TextCharAttribList& rAttribs = pNode->GetCharAttribs(); 2823*cdf0e10cSrcweir sal_uInt16 nAttrCount = rAttribs.Count(); 2824*cdf0e10cSrcweir for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr) 2825*cdf0e10cSrcweir { 2826*cdf0e10cSrcweir if(rAttribs.GetAttrib( nAttr - 1 ) == &rAttrib) 2827*cdf0e10cSrcweir { 2828*cdf0e10cSrcweir rAttribs.RemoveAttrib( nAttr -1 ); 2829*cdf0e10cSrcweir break; 2830*cdf0e10cSrcweir } 2831*cdf0e10cSrcweir } 2832*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 2833*cdf0e10cSrcweir pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); 2834*cdf0e10cSrcweir mbFormatted = sal_False; 2835*cdf0e10cSrcweir FormatAndUpdate( NULL ); 2836*cdf0e10cSrcweir } 2837*cdf0e10cSrcweir } 2838*cdf0e10cSrcweir } 2839*cdf0e10cSrcweir 2840*cdf0e10cSrcweir void TextEngine::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_Bool bIdleFormatAndUpdate ) 2841*cdf0e10cSrcweir { 2842*cdf0e10cSrcweir // Es wird hier erstmal nicht geprueft, ob sich Attribute ueberlappen! 2843*cdf0e10cSrcweir // Diese Methode ist erstmal nur fuer einen Editor, der fuer eine Zeile 2844*cdf0e10cSrcweir // _schnell_ das Syntax-Highlight einstellen will. 2845*cdf0e10cSrcweir 2846*cdf0e10cSrcweir // Da die TextEngine z.Zt fuer Editoren gedacht ist gibt es auch kein 2847*cdf0e10cSrcweir // Undo fuer Attribute! 2848*cdf0e10cSrcweir 2849*cdf0e10cSrcweir if ( nPara < mpDoc->GetNodes().Count() ) 2850*cdf0e10cSrcweir { 2851*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 2852*cdf0e10cSrcweir TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); 2853*cdf0e10cSrcweir 2854*cdf0e10cSrcweir sal_uInt16 nMax = pNode->GetText().Len(); 2855*cdf0e10cSrcweir if ( nStart > nMax ) 2856*cdf0e10cSrcweir nStart = nMax; 2857*cdf0e10cSrcweir if ( nEnd > nMax ) 2858*cdf0e10cSrcweir nEnd = nMax; 2859*cdf0e10cSrcweir 2860*cdf0e10cSrcweir pNode->GetCharAttribs().InsertAttrib( new TextCharAttrib( rAttr, nStart, nEnd ) ); 2861*cdf0e10cSrcweir pTEParaPortion->MarkSelectionInvalid( nStart, nEnd ); 2862*cdf0e10cSrcweir 2863*cdf0e10cSrcweir mbFormatted = sal_False; 2864*cdf0e10cSrcweir if ( bIdleFormatAndUpdate ) 2865*cdf0e10cSrcweir IdleFormatAndUpdate( NULL, 0xFFFF ); 2866*cdf0e10cSrcweir else 2867*cdf0e10cSrcweir FormatAndUpdate( NULL ); 2868*cdf0e10cSrcweir } 2869*cdf0e10cSrcweir } 2870*cdf0e10cSrcweir 2871*cdf0e10cSrcweir void TextEngine::SetTextAlign( TxtAlign eAlign ) 2872*cdf0e10cSrcweir { 2873*cdf0e10cSrcweir if ( eAlign != meAlign ) 2874*cdf0e10cSrcweir { 2875*cdf0e10cSrcweir meAlign = eAlign; 2876*cdf0e10cSrcweir FormatFullDoc(); 2877*cdf0e10cSrcweir UpdateViews(); 2878*cdf0e10cSrcweir } 2879*cdf0e10cSrcweir } 2880*cdf0e10cSrcweir 2881*cdf0e10cSrcweir 2882*cdf0e10cSrcweir void TextEngine::ValidateSelection( TextSelection& rSel ) const 2883*cdf0e10cSrcweir { 2884*cdf0e10cSrcweir ValidatePaM( rSel.GetStart() ); 2885*cdf0e10cSrcweir ValidatePaM( rSel.GetEnd() ); 2886*cdf0e10cSrcweir } 2887*cdf0e10cSrcweir 2888*cdf0e10cSrcweir void TextEngine::ValidatePaM( TextPaM& rPaM ) const 2889*cdf0e10cSrcweir { 2890*cdf0e10cSrcweir sal_uLong nMaxPara = mpDoc->GetNodes().Count() - 1; 2891*cdf0e10cSrcweir if ( rPaM.GetPara() > nMaxPara ) 2892*cdf0e10cSrcweir { 2893*cdf0e10cSrcweir rPaM.GetPara() = nMaxPara; 2894*cdf0e10cSrcweir rPaM.GetIndex() = 0xFFFF; 2895*cdf0e10cSrcweir } 2896*cdf0e10cSrcweir 2897*cdf0e10cSrcweir sal_uInt16 nMaxIndex = GetTextLen( rPaM.GetPara() ); 2898*cdf0e10cSrcweir if ( rPaM.GetIndex() > nMaxIndex ) 2899*cdf0e10cSrcweir rPaM.GetIndex() = nMaxIndex; 2900*cdf0e10cSrcweir } 2901*cdf0e10cSrcweir 2902*cdf0e10cSrcweir 2903*cdf0e10cSrcweir // Status & Selektionsanpassung 2904*cdf0e10cSrcweir 2905*cdf0e10cSrcweir void TextEngine::ImpParagraphInserted( sal_uLong nPara ) 2906*cdf0e10cSrcweir { 2907*cdf0e10cSrcweir // Die aktive View braucht nicht angepasst werden, aber bei allen 2908*cdf0e10cSrcweir // passiven muss die Selektion angepasst werden: 2909*cdf0e10cSrcweir if ( mpViews->Count() > 1 ) 2910*cdf0e10cSrcweir { 2911*cdf0e10cSrcweir for ( sal_uInt16 nView = mpViews->Count(); nView; ) 2912*cdf0e10cSrcweir { 2913*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( --nView ); 2914*cdf0e10cSrcweir if ( pView != GetActiveView() ) 2915*cdf0e10cSrcweir { 2916*cdf0e10cSrcweir // sal_Bool bInvers = pView->maSelection.GetEnd() < pView->maSelection.GetStart(); 2917*cdf0e10cSrcweir // TextPaM& rMin = !bInvers ? pView->maSelection.GetStart(): pView->maSelection.GetEnd(); 2918*cdf0e10cSrcweir // TextPaM& rMax = bInvers ? pView->maSelection.GetStart() : pView->maSelection.GetEnd(); 2919*cdf0e10cSrcweir // 2920*cdf0e10cSrcweir // if ( rMin.GetPara() >= nPara ) 2921*cdf0e10cSrcweir // rMin.GetPara()++; 2922*cdf0e10cSrcweir // if ( rMax.GetPara() >= nPara ) 2923*cdf0e10cSrcweir // rMax.GetPara()++; 2924*cdf0e10cSrcweir for ( int n = 0; n <= 1; n++ ) 2925*cdf0e10cSrcweir { 2926*cdf0e10cSrcweir TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); 2927*cdf0e10cSrcweir if ( rPaM.GetPara() >= nPara ) 2928*cdf0e10cSrcweir rPaM.GetPara()++; 2929*cdf0e10cSrcweir } 2930*cdf0e10cSrcweir } 2931*cdf0e10cSrcweir } 2932*cdf0e10cSrcweir } 2933*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_PARAINSERTED, nPara ) ); 2934*cdf0e10cSrcweir } 2935*cdf0e10cSrcweir 2936*cdf0e10cSrcweir void TextEngine::ImpParagraphRemoved( sal_uLong nPara ) 2937*cdf0e10cSrcweir { 2938*cdf0e10cSrcweir if ( mpViews->Count() > 1 ) 2939*cdf0e10cSrcweir { 2940*cdf0e10cSrcweir for ( sal_uInt16 nView = mpViews->Count(); nView; ) 2941*cdf0e10cSrcweir { 2942*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( --nView ); 2943*cdf0e10cSrcweir if ( pView != GetActiveView() ) 2944*cdf0e10cSrcweir { 2945*cdf0e10cSrcweir sal_uLong nParas = mpDoc->GetNodes().Count(); 2946*cdf0e10cSrcweir for ( int n = 0; n <= 1; n++ ) 2947*cdf0e10cSrcweir { 2948*cdf0e10cSrcweir TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); 2949*cdf0e10cSrcweir if ( rPaM.GetPara() > nPara ) 2950*cdf0e10cSrcweir rPaM.GetPara()--; 2951*cdf0e10cSrcweir else if ( rPaM.GetPara() == nPara ) 2952*cdf0e10cSrcweir { 2953*cdf0e10cSrcweir rPaM.GetIndex() = 0; 2954*cdf0e10cSrcweir if ( rPaM.GetPara() >= nParas ) 2955*cdf0e10cSrcweir rPaM.GetPara()--; 2956*cdf0e10cSrcweir } 2957*cdf0e10cSrcweir } 2958*cdf0e10cSrcweir } 2959*cdf0e10cSrcweir } 2960*cdf0e10cSrcweir } 2961*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_PARAREMOVED, nPara ) ); 2962*cdf0e10cSrcweir } 2963*cdf0e10cSrcweir 2964*cdf0e10cSrcweir void TextEngine::ImpCharsRemoved( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ) 2965*cdf0e10cSrcweir { 2966*cdf0e10cSrcweir if ( mpViews->Count() > 1 ) 2967*cdf0e10cSrcweir { 2968*cdf0e10cSrcweir for ( sal_uInt16 nView = mpViews->Count(); nView; ) 2969*cdf0e10cSrcweir { 2970*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( --nView ); 2971*cdf0e10cSrcweir if ( pView != GetActiveView() ) 2972*cdf0e10cSrcweir { 2973*cdf0e10cSrcweir sal_uInt16 nEnd = nPos+nChars; 2974*cdf0e10cSrcweir for ( int n = 0; n <= 1; n++ ) 2975*cdf0e10cSrcweir { 2976*cdf0e10cSrcweir TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); 2977*cdf0e10cSrcweir if ( rPaM.GetPara() == nPara ) 2978*cdf0e10cSrcweir { 2979*cdf0e10cSrcweir if ( rPaM.GetIndex() > nEnd ) 2980*cdf0e10cSrcweir rPaM.GetIndex() = rPaM.GetIndex() - nChars; 2981*cdf0e10cSrcweir else if ( rPaM.GetIndex() > nPos ) 2982*cdf0e10cSrcweir rPaM.GetIndex() = nPos; 2983*cdf0e10cSrcweir } 2984*cdf0e10cSrcweir } 2985*cdf0e10cSrcweir } 2986*cdf0e10cSrcweir } 2987*cdf0e10cSrcweir } 2988*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) ); 2989*cdf0e10cSrcweir } 2990*cdf0e10cSrcweir 2991*cdf0e10cSrcweir void TextEngine::ImpCharsInserted( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ) 2992*cdf0e10cSrcweir { 2993*cdf0e10cSrcweir if ( mpViews->Count() > 1 ) 2994*cdf0e10cSrcweir { 2995*cdf0e10cSrcweir for ( sal_uInt16 nView = mpViews->Count(); nView; ) 2996*cdf0e10cSrcweir { 2997*cdf0e10cSrcweir TextView* pView = mpViews->GetObject( --nView ); 2998*cdf0e10cSrcweir if ( pView != GetActiveView() ) 2999*cdf0e10cSrcweir { 3000*cdf0e10cSrcweir for ( int n = 0; n <= 1; n++ ) 3001*cdf0e10cSrcweir { 3002*cdf0e10cSrcweir TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); 3003*cdf0e10cSrcweir if ( rPaM.GetPara() == nPara ) 3004*cdf0e10cSrcweir { 3005*cdf0e10cSrcweir if ( rPaM.GetIndex() >= nPos ) 3006*cdf0e10cSrcweir rPaM.GetIndex() = rPaM.GetIndex() + nChars; 3007*cdf0e10cSrcweir } 3008*cdf0e10cSrcweir } 3009*cdf0e10cSrcweir } 3010*cdf0e10cSrcweir } 3011*cdf0e10cSrcweir } 3012*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) ); 3013*cdf0e10cSrcweir } 3014*cdf0e10cSrcweir 3015*cdf0e10cSrcweir void TextEngine::ImpFormattingParagraph( sal_uLong nPara ) 3016*cdf0e10cSrcweir { 3017*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_FORMATPARA, nPara ) ); 3018*cdf0e10cSrcweir } 3019*cdf0e10cSrcweir 3020*cdf0e10cSrcweir void TextEngine::ImpTextHeightChanged() 3021*cdf0e10cSrcweir { 3022*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_TEXTHEIGHTCHANGED ) ); 3023*cdf0e10cSrcweir } 3024*cdf0e10cSrcweir 3025*cdf0e10cSrcweir void TextEngine::ImpTextFormatted() 3026*cdf0e10cSrcweir { 3027*cdf0e10cSrcweir Broadcast( TextHint( TEXT_HINT_TEXTFORMATTED ) ); 3028*cdf0e10cSrcweir } 3029*cdf0e10cSrcweir 3030*cdf0e10cSrcweir void TextEngine::Draw( OutputDevice* pDev, const Point& rPos ) 3031*cdf0e10cSrcweir { 3032*cdf0e10cSrcweir ImpPaint( pDev, rPos, NULL ); 3033*cdf0e10cSrcweir } 3034*cdf0e10cSrcweir 3035*cdf0e10cSrcweir void TextEngine::SetLeftMargin( sal_uInt16 n ) 3036*cdf0e10cSrcweir { 3037*cdf0e10cSrcweir mpDoc->SetLeftMargin( n ); 3038*cdf0e10cSrcweir } 3039*cdf0e10cSrcweir 3040*cdf0e10cSrcweir sal_uInt16 TextEngine::GetLeftMargin() const 3041*cdf0e10cSrcweir { 3042*cdf0e10cSrcweir return mpDoc->GetLeftMargin(); 3043*cdf0e10cSrcweir } 3044*cdf0e10cSrcweir 3045*cdf0e10cSrcweir uno::Reference< i18n::XBreakIterator > TextEngine::GetBreakIterator() 3046*cdf0e10cSrcweir { 3047*cdf0e10cSrcweir if ( !mxBreakIterator.is() ) 3048*cdf0e10cSrcweir mxBreakIterator = vcl::unohelper::CreateBreakIterator(); 3049*cdf0e10cSrcweir DBG_ASSERT( mxBreakIterator.is(), "Could not create BreakIterator" ); 3050*cdf0e10cSrcweir return mxBreakIterator; 3051*cdf0e10cSrcweir } 3052*cdf0e10cSrcweir 3053*cdf0e10cSrcweir void TextEngine::SetLocale( const ::com::sun::star::lang::Locale& rLocale ) 3054*cdf0e10cSrcweir { 3055*cdf0e10cSrcweir maLocale = rLocale; 3056*cdf0e10cSrcweir delete mpLocaleDataWrapper; 3057*cdf0e10cSrcweir mpLocaleDataWrapper = NULL; 3058*cdf0e10cSrcweir } 3059*cdf0e10cSrcweir 3060*cdf0e10cSrcweir ::com::sun::star::lang::Locale TextEngine::GetLocale() 3061*cdf0e10cSrcweir { 3062*cdf0e10cSrcweir if ( !maLocale.Language.getLength() ) 3063*cdf0e10cSrcweir { 3064*cdf0e10cSrcweir maLocale = Application::GetSettings().GetUILocale(); 3065*cdf0e10cSrcweir } 3066*cdf0e10cSrcweir return maLocale; 3067*cdf0e10cSrcweir } 3068*cdf0e10cSrcweir 3069*cdf0e10cSrcweir LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper() 3070*cdf0e10cSrcweir { 3071*cdf0e10cSrcweir if ( !mpLocaleDataWrapper ) 3072*cdf0e10cSrcweir mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() ); 3073*cdf0e10cSrcweir 3074*cdf0e10cSrcweir return mpLocaleDataWrapper; 3075*cdf0e10cSrcweir } 3076*cdf0e10cSrcweir 3077*cdf0e10cSrcweir void TextEngine::SetRightToLeft( sal_Bool bR2L ) 3078*cdf0e10cSrcweir { 3079*cdf0e10cSrcweir if ( mbRightToLeft != bR2L ) 3080*cdf0e10cSrcweir { 3081*cdf0e10cSrcweir mbRightToLeft = bR2L; 3082*cdf0e10cSrcweir meAlign = bR2L ? TXTALIGN_RIGHT : TXTALIGN_LEFT; 3083*cdf0e10cSrcweir FormatFullDoc(); 3084*cdf0e10cSrcweir UpdateViews(); 3085*cdf0e10cSrcweir } 3086*cdf0e10cSrcweir } 3087*cdf0e10cSrcweir 3088*cdf0e10cSrcweir void TextEngine::ImpInitWritingDirections( sal_uLong nPara ) 3089*cdf0e10cSrcweir { 3090*cdf0e10cSrcweir TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); 3091*cdf0e10cSrcweir TEWritingDirectionInfos& rInfos = pParaPortion->GetWritingDirectionInfos(); 3092*cdf0e10cSrcweir rInfos.Remove( 0, rInfos.Count() ); 3093*cdf0e10cSrcweir 3094*cdf0e10cSrcweir if ( pParaPortion->GetNode()->GetText().Len() ) 3095*cdf0e10cSrcweir { 3096*cdf0e10cSrcweir const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/; 3097*cdf0e10cSrcweir String aText( pParaPortion->GetNode()->GetText() ); 3098*cdf0e10cSrcweir 3099*cdf0e10cSrcweir // 3100*cdf0e10cSrcweir // Bidi functions from icu 2.0 3101*cdf0e10cSrcweir // 3102*cdf0e10cSrcweir UErrorCode nError = U_ZERO_ERROR; 3103*cdf0e10cSrcweir UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError ); 3104*cdf0e10cSrcweir nError = U_ZERO_ERROR; 3105*cdf0e10cSrcweir 3106*cdf0e10cSrcweir ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW 3107*cdf0e10cSrcweir nError = U_ZERO_ERROR; 3108*cdf0e10cSrcweir 3109*cdf0e10cSrcweir long nCount = ubidi_countRuns( pBidi, &nError ); 3110*cdf0e10cSrcweir 3111*cdf0e10cSrcweir int32_t nStart = 0; 3112*cdf0e10cSrcweir int32_t nEnd; 3113*cdf0e10cSrcweir UBiDiLevel nCurrDir; 3114*cdf0e10cSrcweir 3115*cdf0e10cSrcweir for ( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx ) 3116*cdf0e10cSrcweir { 3117*cdf0e10cSrcweir ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir ); 3118*cdf0e10cSrcweir rInfos.Insert( TEWritingDirectionInfo( nCurrDir, (sal_uInt16)nStart, (sal_uInt16)nEnd ), rInfos.Count() ); 3119*cdf0e10cSrcweir nStart = nEnd; 3120*cdf0e10cSrcweir } 3121*cdf0e10cSrcweir 3122*cdf0e10cSrcweir ubidi_close( pBidi ); 3123*cdf0e10cSrcweir } 3124*cdf0e10cSrcweir 3125*cdf0e10cSrcweir // No infos mean no CTL and default dir is L2R... 3126*cdf0e10cSrcweir if ( !rInfos.Count() ) 3127*cdf0e10cSrcweir rInfos.Insert( TEWritingDirectionInfo( 0, 0, (sal_uInt16)pParaPortion->GetNode()->GetText().Len() ), rInfos.Count() ); 3128*cdf0e10cSrcweir 3129*cdf0e10cSrcweir } 3130*cdf0e10cSrcweir 3131*cdf0e10cSrcweir sal_uInt8 TextEngine::ImpGetRightToLeft( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16* pStart, sal_uInt16* pEnd ) 3132*cdf0e10cSrcweir { 3133*cdf0e10cSrcweir sal_uInt8 nRightToLeft = 0; 3134*cdf0e10cSrcweir 3135*cdf0e10cSrcweir TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); 3136*cdf0e10cSrcweir if ( pNode && pNode->GetText().Len() ) 3137*cdf0e10cSrcweir { 3138*cdf0e10cSrcweir TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); 3139*cdf0e10cSrcweir if ( !pParaPortion->GetWritingDirectionInfos().Count() ) 3140*cdf0e10cSrcweir ImpInitWritingDirections( nPara ); 3141*cdf0e10cSrcweir 3142*cdf0e10cSrcweir TEWritingDirectionInfos& rDirInfos = pParaPortion->GetWritingDirectionInfos(); 3143*cdf0e10cSrcweir for ( sal_uInt16 n = 0; n < rDirInfos.Count(); n++ ) 3144*cdf0e10cSrcweir { 3145*cdf0e10cSrcweir if ( ( rDirInfos[n].nStartPos <= nPos ) && ( rDirInfos[n].nEndPos >= nPos ) ) 3146*cdf0e10cSrcweir { 3147*cdf0e10cSrcweir nRightToLeft = rDirInfos[n].nType; 3148*cdf0e10cSrcweir if ( pStart ) 3149*cdf0e10cSrcweir *pStart = rDirInfos[n].nStartPos; 3150*cdf0e10cSrcweir if ( pEnd ) 3151*cdf0e10cSrcweir *pEnd = rDirInfos[n].nEndPos; 3152*cdf0e10cSrcweir break; 3153*cdf0e10cSrcweir } 3154*cdf0e10cSrcweir } 3155*cdf0e10cSrcweir } 3156*cdf0e10cSrcweir return nRightToLeft; 3157*cdf0e10cSrcweir } 3158*cdf0e10cSrcweir 3159*cdf0e10cSrcweir long TextEngine::ImpGetPortionXOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nTextPortion ) 3160*cdf0e10cSrcweir { 3161*cdf0e10cSrcweir long nX = pLine->GetStartX(); 3162*cdf0e10cSrcweir 3163*cdf0e10cSrcweir TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); 3164*cdf0e10cSrcweir 3165*cdf0e10cSrcweir for ( sal_uInt16 i = pLine->GetStartPortion(); i < nTextPortion; i++ ) 3166*cdf0e10cSrcweir { 3167*cdf0e10cSrcweir TETextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( i ); 3168*cdf0e10cSrcweir nX += pPortion->GetWidth(); 3169*cdf0e10cSrcweir } 3170*cdf0e10cSrcweir 3171*cdf0e10cSrcweir TETextPortion* pDestPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); 3172*cdf0e10cSrcweir if ( pDestPortion->GetKind() != PORTIONKIND_TAB ) 3173*cdf0e10cSrcweir { 3174*cdf0e10cSrcweir if ( !IsRightToLeft() && pDestPortion->GetRightToLeft() ) 3175*cdf0e10cSrcweir { 3176*cdf0e10cSrcweir // Portions behind must be added, visual before this portion 3177*cdf0e10cSrcweir sal_uInt16 nTmpPortion = nTextPortion+1; 3178*cdf0e10cSrcweir while ( nTmpPortion <= pLine->GetEndPortion() ) 3179*cdf0e10cSrcweir { 3180*cdf0e10cSrcweir TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); 3181*cdf0e10cSrcweir if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) 3182*cdf0e10cSrcweir nX += pNextTextPortion->GetWidth(); 3183*cdf0e10cSrcweir else 3184*cdf0e10cSrcweir break; 3185*cdf0e10cSrcweir nTmpPortion++; 3186*cdf0e10cSrcweir } 3187*cdf0e10cSrcweir // Portions before must be removed, visual behind this portion 3188*cdf0e10cSrcweir nTmpPortion = nTextPortion; 3189*cdf0e10cSrcweir while ( nTmpPortion > pLine->GetStartPortion() ) 3190*cdf0e10cSrcweir { 3191*cdf0e10cSrcweir --nTmpPortion; 3192*cdf0e10cSrcweir TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); 3193*cdf0e10cSrcweir if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) 3194*cdf0e10cSrcweir nX -= pPrevTextPortion->GetWidth(); 3195*cdf0e10cSrcweir else 3196*cdf0e10cSrcweir break; 3197*cdf0e10cSrcweir } 3198*cdf0e10cSrcweir } 3199*cdf0e10cSrcweir else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() ) 3200*cdf0e10cSrcweir { 3201*cdf0e10cSrcweir // Portions behind must be removed, visual behind this portion 3202*cdf0e10cSrcweir sal_uInt16 nTmpPortion = nTextPortion+1; 3203*cdf0e10cSrcweir while ( nTmpPortion <= pLine->GetEndPortion() ) 3204*cdf0e10cSrcweir { 3205*cdf0e10cSrcweir TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); 3206*cdf0e10cSrcweir if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) 3207*cdf0e10cSrcweir nX += pNextTextPortion->GetWidth(); 3208*cdf0e10cSrcweir else 3209*cdf0e10cSrcweir break; 3210*cdf0e10cSrcweir nTmpPortion++; 3211*cdf0e10cSrcweir } 3212*cdf0e10cSrcweir // Portions before must be added, visual before this portion 3213*cdf0e10cSrcweir nTmpPortion = nTextPortion; 3214*cdf0e10cSrcweir while ( nTmpPortion > pLine->GetStartPortion() ) 3215*cdf0e10cSrcweir { 3216*cdf0e10cSrcweir --nTmpPortion; 3217*cdf0e10cSrcweir TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); 3218*cdf0e10cSrcweir if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) 3219*cdf0e10cSrcweir nX -= pPrevTextPortion->GetWidth(); 3220*cdf0e10cSrcweir else 3221*cdf0e10cSrcweir break; 3222*cdf0e10cSrcweir } 3223*cdf0e10cSrcweir } 3224*cdf0e10cSrcweir } 3225*cdf0e10cSrcweir /* 3226*cdf0e10cSrcweir if ( IsRightToLeft() ) 3227*cdf0e10cSrcweir { 3228*cdf0e10cSrcweir // Switch X postions... 3229*cdf0e10cSrcweir DBG_ASSERT( GetMaxTextWidth(), "GetPortionXOffset - max text width?!" ); 3230*cdf0e10cSrcweir DBG_ASSERT( nX <= (long)GetMaxTextWidth(), "GetPortionXOffset - position out of paper size!" ); 3231*cdf0e10cSrcweir nX = GetMaxTextWidth() - nX; 3232*cdf0e10cSrcweir nX -= pDestPortion->GetWidth(); 3233*cdf0e10cSrcweir } 3234*cdf0e10cSrcweir */ 3235*cdf0e10cSrcweir 3236*cdf0e10cSrcweir return nX; 3237*cdf0e10cSrcweir } 3238*cdf0e10cSrcweir 3239*cdf0e10cSrcweir void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev, sal_Bool bDrawingR2LPortion ) 3240*cdf0e10cSrcweir { 3241*cdf0e10cSrcweir sal_uLong nLayoutMode = pOutDev->GetLayoutMode(); 3242*cdf0e10cSrcweir 3243*cdf0e10cSrcweir nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); 3244*cdf0e10cSrcweir if ( bDrawingR2LPortion ) 3245*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; 3246*cdf0e10cSrcweir 3247*cdf0e10cSrcweir pOutDev->SetLayoutMode( nLayoutMode ); 3248*cdf0e10cSrcweir } 3249*cdf0e10cSrcweir 3250*cdf0e10cSrcweir TxtAlign TextEngine::ImpGetAlign() const 3251*cdf0e10cSrcweir { 3252*cdf0e10cSrcweir TxtAlign eAlign = meAlign; 3253*cdf0e10cSrcweir if ( IsRightToLeft() ) 3254*cdf0e10cSrcweir { 3255*cdf0e10cSrcweir if ( eAlign == TXTALIGN_LEFT ) 3256*cdf0e10cSrcweir eAlign = TXTALIGN_RIGHT; 3257*cdf0e10cSrcweir else if ( eAlign == TXTALIGN_RIGHT ) 3258*cdf0e10cSrcweir eAlign = TXTALIGN_LEFT; 3259*cdf0e10cSrcweir } 3260*cdf0e10cSrcweir return eAlign; 3261*cdf0e10cSrcweir } 3262*cdf0e10cSrcweir 3263*cdf0e10cSrcweir long TextEngine::ImpGetOutputOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_uInt16 nIndex2 ) 3264*cdf0e10cSrcweir { 3265*cdf0e10cSrcweir TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); 3266*cdf0e10cSrcweir 3267*cdf0e10cSrcweir sal_uInt16 nPortionStart; 3268*cdf0e10cSrcweir sal_uInt16 nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, sal_True ); 3269*cdf0e10cSrcweir 3270*cdf0e10cSrcweir TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( nPortion ); 3271*cdf0e10cSrcweir 3272*cdf0e10cSrcweir long nX; 3273*cdf0e10cSrcweir 3274*cdf0e10cSrcweir if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 ) ) 3275*cdf0e10cSrcweir { 3276*cdf0e10cSrcweir // Output of full portion, so we need portion x offset. 3277*cdf0e10cSrcweir // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portioon, depending on R2L, L2R 3278*cdf0e10cSrcweir nX = ImpGetPortionXOffset( nPara, pLine, nPortion ); 3279*cdf0e10cSrcweir if ( IsRightToLeft() ) 3280*cdf0e10cSrcweir { 3281*cdf0e10cSrcweir nX = -nX -pTextPortion->GetWidth(); 3282*cdf0e10cSrcweir } 3283*cdf0e10cSrcweir } 3284*cdf0e10cSrcweir else 3285*cdf0e10cSrcweir { 3286*cdf0e10cSrcweir nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart ); 3287*cdf0e10cSrcweir if ( nIndex2 != nIndex ) 3288*cdf0e10cSrcweir { 3289*cdf0e10cSrcweir long nX2 = ImpGetXPos( nPara, pLine, nIndex2, sal_False ); 3290*cdf0e10cSrcweir if ( ( !IsRightToLeft() && ( nX2 < nX ) ) || 3291*cdf0e10cSrcweir ( IsRightToLeft() && ( nX2 > nX ) ) ) 3292*cdf0e10cSrcweir { 3293*cdf0e10cSrcweir nX = nX2; 3294*cdf0e10cSrcweir } 3295*cdf0e10cSrcweir } 3296*cdf0e10cSrcweir if ( IsRightToLeft() ) 3297*cdf0e10cSrcweir { 3298*cdf0e10cSrcweir nX = -nX; 3299*cdf0e10cSrcweir } 3300*cdf0e10cSrcweir } 3301*cdf0e10cSrcweir 3302*cdf0e10cSrcweir return nX; 3303*cdf0e10cSrcweir } 3304