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