xref: /AOO41X/main/svtools/source/edit/texteng.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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