xref: /trunk/main/svtools/source/edit/textview.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 #include <svtools/textview.hxx>
31 #include <svtools/texteng.hxx>
32 #include <textdoc.hxx>
33 #include <svtools/textdata.hxx>
34 #include <textdat2.hxx>
35 
36 #include <svl/undo.hxx>
37 #include <vcl/cursor.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/sound.hxx>
41 #include <tools/stream.hxx>
42 
43 #include <sot/formats.hxx>
44 #include <svl/urlbmk.hxx>
45 
46 #ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_
47 #include <com/sun/star/i18n/XBreakIterator.hpp>
48 #endif
49 
50 #ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_
51 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
52 #endif
53 
54 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
55 #include <com/sun/star/i18n/WordType.hpp>
56 #endif
57 #include <cppuhelper/weak.hxx>
58 #include <vcl/unohelp.hxx>
59 #include <com/sun/star/datatransfer/XTransferable.hpp>
60 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
61 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
62 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
63 
64 #ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_
65 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
66 #endif
67 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
68 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
69 
70 #include <vcl/edit.hxx>
71 
72 
73 #include <sot/exchange.hxx>
74 #include <sot/formats.hxx>
75 
76 #include <vos/mutex.hxx>
77 
78 
79 using namespace ::com::sun::star;
80 
81 class TETextDataObject :    public ::com::sun::star::datatransfer::XTransferable,
82                         public ::cppu::OWeakObject
83 
84 {
85 private:
86     String          maText;
87     SvMemoryStream  maHTMLStream;
88 
89 public:
90                     TETextDataObject( const String& rText );
91                     ~TETextDataObject();
92 
93     String&         GetText() { return maText; }
94     SvMemoryStream& GetHTMLStream() { return maHTMLStream; }
95 
96     // ::com::sun::star::uno::XInterface
97     ::com::sun::star::uno::Any                  SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
98     void                                        SAL_CALL acquire() throw()  { OWeakObject::acquire(); }
99     void                                        SAL_CALL release() throw()  { OWeakObject::release(); }
100 
101     // ::com::sun::star::datatransfer::XTransferable
102     ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
103     ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors(  ) throw(::com::sun::star::uno::RuntimeException);
104     sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException);
105 };
106 
107 TETextDataObject::TETextDataObject( const String& rText ) : maText( rText )
108 {
109 }
110 
111 TETextDataObject::~TETextDataObject()
112 {
113 }
114 
115 // uno::XInterface
116 uno::Any TETextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException)
117 {
118     uno::Any aRet = ::cppu::queryInterface( rType, SAL_STATIC_CAST( datatransfer::XTransferable*, this ) );
119     return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
120 }
121 
122 // datatransfer::XTransferable
123 uno::Any TETextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException)
124 {
125     uno::Any aAny;
126 
127     sal_uLong nT = SotExchange::GetFormat( rFlavor );
128     if ( nT == SOT_FORMAT_STRING )
129     {
130         aAny <<= (::rtl::OUString)GetText();
131     }
132     else if ( nT == SOT_FORMATSTR_ID_HTML )
133     {
134         GetHTMLStream().Seek( STREAM_SEEK_TO_END );
135         sal_uLong nLen = GetHTMLStream().Tell();
136         GetHTMLStream().Seek(0);
137 
138         uno::Sequence< sal_Int8 > aSeq( nLen );
139         memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen );
140         aAny <<= aSeq;
141     }
142     else
143     {
144         throw datatransfer::UnsupportedFlavorException();
145     }
146     return aAny;
147 }
148 
149 uno::Sequence< datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors(  ) throw(uno::RuntimeException)
150 {
151     GetHTMLStream().Seek( STREAM_SEEK_TO_END );
152     sal_Bool bHTML = GetHTMLStream().Tell() > 0;
153     uno::Sequence< datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 );
154     SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] );
155     if ( bHTML )
156         SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_HTML, aDataFlavors.getArray()[1] );
157     return aDataFlavors;
158 }
159 
160 sal_Bool TETextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException)
161 {
162     sal_uLong nT = SotExchange::GetFormat( rFlavor );
163     return ( nT == SOT_FORMAT_STRING );
164 }
165 
166 /*-- 24.06.2004 13:54:36---------------------------------------------------
167 
168   -----------------------------------------------------------------------*/
169 struct ImpTextView
170 {
171     TextEngine*         mpTextEngine;
172 
173     Window*             mpWindow;
174     TextSelection       maSelection;
175     Point               maStartDocPos;
176 //    TextPaM             maMBDownPaM;
177 
178     Cursor*             mpCursor;
179 
180     TextDDInfo*         mpDDInfo;
181 
182     VirtualDevice*      mpVirtDev;
183 
184     SelectionEngine*    mpSelEngine;
185     TextSelFunctionSet* mpSelFuncSet;
186 
187     ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener;
188 
189     sal_uInt16              mnTravelXPos;
190 
191     sal_Bool                mbAutoScroll            : 1;
192     sal_Bool                mbInsertMode            : 1;
193     sal_Bool                mbReadOnly              : 1;
194     sal_Bool                mbPaintSelection        : 1;
195     sal_Bool                mbAutoIndent            : 1;
196     sal_Bool                mbHighlightSelection    : 1;
197     sal_Bool                mbCursorEnabled         : 1;
198     sal_Bool                mbClickedInSelection    : 1;
199     sal_Bool                mbSupportProtectAttribute : 1;
200     bool                mbCursorAtEndOfLine;
201 };
202 
203 // -------------------------------------------------------------------------
204 // (+) class TextView
205 // -------------------------------------------------------------------------
206 TextView::TextView( TextEngine* pEng, Window* pWindow ) :
207     mpImpl(new ImpTextView)
208 {
209     pWindow->EnableRTL( sal_False );
210 
211     mpImpl->mpWindow = pWindow;
212     mpImpl->mpTextEngine = pEng;
213     mpImpl->mpVirtDev = NULL;
214 
215     mpImpl->mbPaintSelection = sal_True;
216     mpImpl->mbAutoScroll = sal_True;
217     mpImpl->mbInsertMode = sal_True;
218     mpImpl->mbReadOnly = sal_False;
219     mpImpl->mbHighlightSelection = sal_False;
220     mpImpl->mbAutoIndent = sal_False;
221     mpImpl->mbCursorEnabled = sal_True;
222     mpImpl->mbClickedInSelection = sal_False;
223     mpImpl->mbSupportProtectAttribute = sal_False;
224     mpImpl->mbCursorAtEndOfLine = false;
225 //  mbInSelection = sal_False;
226 
227     mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
228 
229     mpImpl->mpSelFuncSet = new TextSelFunctionSet( this );
230     mpImpl->mpSelEngine = new SelectionEngine( mpImpl->mpWindow, mpImpl->mpSelFuncSet );
231     mpImpl->mpSelEngine->SetSelectionMode( RANGE_SELECTION );
232     mpImpl->mpSelEngine->EnableDrag( sal_True );
233 
234     mpImpl->mpCursor = new Cursor;
235     mpImpl->mpCursor->Show();
236     pWindow->SetCursor( mpImpl->mpCursor );
237     pWindow->SetInputContext( InputContext( pEng->GetFont(), INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT ) );
238 
239     if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT )
240         mpImpl->mbHighlightSelection = sal_True;
241 
242     pWindow->SetLineColor();
243 
244     mpImpl->mpDDInfo = NULL;
245 
246     if ( pWindow->GetDragGestureRecognizer().is() )
247     {
248         vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
249         mpImpl->mxDnDListener = pDnDWrapper;
250 
251         uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, uno::UNO_QUERY );
252         pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL );
253         uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY );
254         pWindow->GetDropTarget()->addDropTargetListener( xDTL );
255         pWindow->GetDropTarget()->setActive( sal_True );
256         pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
257     }
258 }
259 
260 TextView::~TextView()
261 {
262     delete mpImpl->mpSelEngine;
263     delete mpImpl->mpSelFuncSet;
264     delete mpImpl->mpVirtDev;
265 
266     if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor )
267         mpImpl->mpWindow->SetCursor( 0 );
268     delete mpImpl->mpCursor;
269     delete mpImpl->mpDDInfo;
270     delete mpImpl;
271 }
272 
273 void TextView::Invalidate()
274 {
275     mpImpl->mpWindow->Invalidate();
276 }
277 
278 void TextView::SetSelection( const TextSelection& rTextSel, sal_Bool bGotoCursor )
279 {
280     // Falls jemand gerade ein leeres Attribut hinterlassen hat,
281     // und dann der Outliner die Selektion manipulitert:
282     if ( !mpImpl->maSelection.HasRange() )
283         mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() );
284 
285     // Wenn nach einem KeyInput die Selection manipuliert wird:
286     mpImpl->mpTextEngine->CheckIdleFormatter();
287 
288     HideSelection();
289     TextSelection aNewSel( rTextSel );
290     mpImpl->mpTextEngine->ValidateSelection( aNewSel );
291     ImpSetSelection( aNewSel );
292     ShowSelection();
293     ShowCursor( bGotoCursor );
294 }
295 
296 void TextView::SetSelection( const TextSelection& rTextSel )
297 {
298     SetSelection( rTextSel, mpImpl->mbAutoScroll );
299 }
300 
301 const TextSelection& TextView::GetSelection() const
302 {
303     return mpImpl->maSelection;
304 }
305 TextSelection&      TextView::GetSelection()
306 {
307     return mpImpl->maSelection;
308 }
309 
310 void TextView::DeleteSelected()
311 {
312 //  HideSelection();
313 
314     mpImpl->mpTextEngine->UndoActionStart();
315     TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
316     mpImpl->mpTextEngine->UndoActionEnd();
317 
318     ImpSetSelection( aPaM );
319     mpImpl->mpTextEngine->FormatAndUpdate( this );
320     ShowCursor();
321 }
322 
323 void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection )
324 {
325     if ( !mpImpl->mbPaintSelection )
326         pSelection = NULL;
327     else
328     {
329         // Richtige Hintergrundfarbe einstellen.
330         // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat.
331         Font aFont = mpImpl->mpTextEngine->GetFont();
332         Color aColor = pOut->GetBackground().GetColor();
333         aColor.SetTransparency( 0 );
334         if ( aColor != aFont.GetFillColor() )
335         {
336             if( aFont.IsTransparent() )
337                 aColor = Color( COL_TRANSPARENT );
338             aFont.SetFillColor( aColor );
339             mpImpl->mpTextEngine->maFont = aFont;
340         }
341     }
342 
343     mpImpl->mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection );
344 }
345 
346 void TextView::Paint( const Rectangle& rRect )
347 {
348     ImpPaint( rRect, sal_False );
349 }
350 
351 void TextView::ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev )
352 {
353     if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() )
354         return;
355 
356     TextSelection *pDrawSelection = NULL;
357     if ( !mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange() )
358         pDrawSelection = &mpImpl->maSelection;
359 
360     if ( bUseVirtDev )
361     {
362         VirtualDevice* pVDev = GetVirtualDevice();
363 
364         const Color& rBackgroundColor = mpImpl->mpWindow->GetBackground().GetColor();
365         if ( pVDev->GetFillColor() != rBackgroundColor )
366             pVDev->SetFillColor( rBackgroundColor );
367         if ( pVDev->GetBackground().GetColor() != rBackgroundColor )
368             pVDev->SetBackground( rBackgroundColor );
369 
370         sal_Bool bVDevValid = sal_True;
371         Size aOutSz( pVDev->GetOutputSizePixel() );
372         if ( (  aOutSz.Width() < rRect.GetWidth() ) ||
373              (  aOutSz.Height() < rRect.GetHeight() ) )
374         {
375             bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() );
376         }
377         else
378         {
379             // Das VirtDev kann bei einem Resize sehr gross werden =>
380             // irgendwann mal kleiner machen!
381             if ( ( aOutSz.Height() > ( rRect.GetHeight() + 20 ) ) ||
382                  ( aOutSz.Width() > ( rRect.GetWidth() + 20 ) ) )
383             {
384                 bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() );
385             }
386             else
387             {
388                 pVDev->Erase();
389             }
390         }
391         if ( !bVDevValid )
392         {
393             ImpPaint( rRect, sal_False /* ohne VDev */ );
394             return;
395         }
396 
397         Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() );
398 
399         Point aDocPos( mpImpl->maStartDocPos.X(), mpImpl->maStartDocPos.Y() + rRect.Top() );
400         Point aStartPos = ImpGetOutputStartPos( aDocPos );
401         ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pDrawSelection );
402         mpImpl->mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(),
403                                 Point(0,0), rRect.GetSize(), *pVDev );
404 //      ShowSelection();
405         if ( mpImpl->mbHighlightSelection )
406             ImpHighlight( mpImpl->maSelection );
407     }
408     else
409     {
410         Point aStartPos = ImpGetOutputStartPos( mpImpl->maStartDocPos );
411         ImpPaint( mpImpl->mpWindow, aStartPos, &rRect, NULL, pDrawSelection );
412 
413 //      ShowSelection();
414         if ( mpImpl->mbHighlightSelection )
415             ImpHighlight( mpImpl->maSelection );
416     }
417 }
418 
419 void TextView::ImpHighlight( const TextSelection& rSel )
420 {
421     TextSelection aSel( rSel );
422     aSel.Justify();
423     if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() )
424     {
425         mpImpl->mpCursor->Hide();
426 
427         DBG_ASSERT( !mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" );
428 
429         Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() );
430         long nY = 0;
431         sal_uLong nStartPara = aSel.GetStart().GetPara();
432         sal_uLong nEndPara = aSel.GetEnd().GetPara();
433         for ( sal_uLong nPara = 0; nPara <= nEndPara; nPara++ )
434         {
435             long nParaHeight = (long)mpImpl->mpTextEngine->CalcParaHeight( nPara );
436             if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) )
437             {
438                 TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara );
439                 sal_uInt16 nStartLine = 0;
440                 sal_uInt16 nEndLine = pTEParaPortion->GetLines().Count() -1;
441                 if ( nPara == nStartPara )
442                     nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), sal_False );
443                 if ( nPara == nEndPara )
444                     nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), sal_True );
445 
446                 // ueber die Zeilen iterieren....
447                 for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ )
448                 {
449                     TextLine* pLine = pTEParaPortion->GetLines().GetObject( nLine );
450                     sal_uInt16 nStartIndex = pLine->GetStart();
451                     sal_uInt16 nEndIndex = pLine->GetEnd();
452                     if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) )
453                         nStartIndex = aSel.GetStart().GetIndex();
454                     if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) )
455                         nEndIndex = aSel.GetEnd().GetIndex();
456 
457                     // Kann passieren, wenn am Anfang einer umgebrochenen Zeile.
458                     if ( nEndIndex < nStartIndex )
459                         nEndIndex = nStartIndex;
460 
461                     Rectangle aTmpRec( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), sal_False ) );
462                     aTmpRec.Top() += nY;
463                     aTmpRec.Bottom() += nY;
464                     Point aTopLeft( aTmpRec.TopLeft() );
465 
466                     aTmpRec = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), sal_True );
467                     aTmpRec.Top() += nY;
468                     aTmpRec.Bottom() += nY;
469                     Point aBottomRight( aTmpRec.BottomRight() );
470                     aBottomRight.X()--;
471 
472                     // Nur Painten, wenn im sichtbaren Bereich...
473                     if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) )
474                     {
475                         Point aPnt1( GetWindowPos( aTopLeft ) );
476                         Point aPnt2( GetWindowPos( aBottomRight ) );
477 
478                         Rectangle aRect( aPnt1, aPnt2 );
479                         mpImpl->mpWindow->Invert( aRect );
480                     }
481                 }
482             }
483             nY += nParaHeight;
484 
485             if ( nY >= aVisArea.Bottom() )
486                 break;
487         }
488     }
489 }
490 
491 void TextView::ImpSetSelection( const TextSelection& rSelection )
492 {
493     if ( rSelection != mpImpl->maSelection )
494     {
495         mpImpl->maSelection = rSelection;
496         mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSELECTIONCHANGED ) );
497     }
498 }
499 
500 void TextView::ShowSelection()
501 {
502     ImpShowHideSelection( sal_True );
503 }
504 
505 void TextView::HideSelection()
506 {
507     ImpShowHideSelection( sal_False );
508 }
509 
510 void TextView::ShowSelection( const TextSelection& rRange )
511 {
512     ImpShowHideSelection( sal_True, &rRange );
513 }
514 
515 void TextView::ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange )
516 {
517     const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection;
518 
519     if ( pRangeOrSelection->HasRange() )
520     {
521         if ( mpImpl->mbHighlightSelection )
522         {
523             ImpHighlight( *pRangeOrSelection );
524         }
525         else
526         {
527             if( mpImpl->mpWindow->IsPaintTransparent() )
528                 mpImpl->mpWindow->Invalidate();
529             else
530             {
531                 Rectangle aOutArea( Point( 0, 0 ), mpImpl->mpWindow->GetOutputSizePixel() );
532                 Point aStartPos( ImpGetOutputStartPos( mpImpl->maStartDocPos ) );
533                 TextSelection aRange( *pRangeOrSelection );
534                 aRange.Justify();
535                 sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible();
536                 mpImpl->mpCursor->Hide();
537                 ImpPaint( mpImpl->mpWindow, aStartPos, &aOutArea, &aRange, bShow ? &mpImpl->maSelection : NULL );
538                 if ( bVisCursor )
539                     mpImpl->mpCursor->Show();
540             }
541         }
542     }
543 }
544 
545 VirtualDevice* TextView::GetVirtualDevice()
546 {
547     if ( !mpImpl->mpVirtDev )
548     {
549         mpImpl->mpVirtDev = new VirtualDevice;
550         mpImpl->mpVirtDev->SetLineColor();
551     }
552     return mpImpl->mpVirtDev;
553 }
554 
555 void TextView::EraseVirtualDevice()
556 {
557     delete mpImpl->mpVirtDev;
558     mpImpl->mpVirtDev = 0;
559 }
560 
561 sal_Bool TextView::KeyInput( const KeyEvent& rKeyEvent )
562 {
563     sal_Bool bDone      = sal_True;
564     sal_Bool bModified  = sal_False;
565     sal_Bool bMoved     = sal_False;
566     sal_Bool bEndKey    = sal_False;    // spezielle CursorPosition
567     sal_Bool bAllowIdle = sal_True;
568 
569     // Um zu pruefen ob durch irgendeine Aktion mModified, das lokale
570     // bModified wird z.B. bei Cut/Paste nicht gesetzt, weil dort an anderen
571     // Stellen das updaten erfolgt.
572     sal_Bool bWasModified = mpImpl->mpTextEngine->IsModified();
573     mpImpl->mpTextEngine->SetModified( sal_False );
574 
575     TextSelection aCurSel( mpImpl->maSelection );
576     TextSelection aOldSel( aCurSel );
577 
578     sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode();
579     KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
580     if ( eFunc != KEYFUNC_DONTKNOW )
581     {
582         switch ( eFunc )
583         {
584             case KEYFUNC_CUT:
585             {
586                 if ( !mpImpl->mbReadOnly )
587                     Cut();
588             }
589             break;
590             case KEYFUNC_COPY:
591             {
592                 Copy();
593             }
594             break;
595             case KEYFUNC_PASTE:
596             {
597                 if ( !mpImpl->mbReadOnly )
598                     Paste();
599             }
600             break;
601             case KEYFUNC_UNDO:
602             {
603                 if ( !mpImpl->mbReadOnly )
604                     Undo();
605             }
606             break;
607             case KEYFUNC_REDO:
608             {
609                 if ( !mpImpl->mbReadOnly )
610                     Redo();
611             }
612             break;
613 
614             default:    // wird dann evtl. unten bearbeitet.
615                         eFunc = KEYFUNC_DONTKNOW;
616         }
617     }
618     if ( eFunc == KEYFUNC_DONTKNOW )
619     {
620         switch ( nCode )
621         {
622             case KEY_UP:
623             case KEY_DOWN:
624             case KEY_LEFT:
625             case KEY_RIGHT:
626             case KEY_HOME:
627             case KEY_END:
628             case KEY_PAGEUP:
629             case KEY_PAGEDOWN:
630             case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
631             case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
632             case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
633             case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
634             case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
635             case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
636             case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
637             case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
638             case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
639             case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
640             case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
641             case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
642             case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
643             case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
644             case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
645             case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
646             {
647                 if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) )
648                       && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) )
649                 {
650                     aCurSel = ImpMoveCursor( rKeyEvent );
651                     if ( aCurSel.HasRange() ) {
652                         uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
653                         Copy( aSelection );
654                     }
655                     bMoved = sal_True;
656                     if ( nCode == KEY_END )
657                         bEndKey = sal_True;
658                 }
659                 else
660                     bDone = sal_False;
661             }
662             break;
663             case KEY_BACKSPACE:
664             case KEY_DELETE:
665             case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
666             case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
667             case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
668             case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
669             {
670                 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() )
671                 {
672                     sal_uInt8 nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT;
673                     sal_uInt8 nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE;
674                     if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() )
675                         nMode = DELMODE_RESTOFCONTENT;
676 
677                     switch( nCode )
678                     {
679                     case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
680                         nDel = DEL_LEFT;
681                         nMode = DELMODE_RESTOFWORD;
682                         break;
683                     case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
684                         nDel = DEL_RIGHT;
685                         nMode = DELMODE_RESTOFWORD;
686                         break;
687                     case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
688                         nDel = DEL_LEFT;
689                         nMode = DELMODE_RESTOFCONTENT;
690                         break;
691                     case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
692                         nDel = DEL_RIGHT;
693                         nMode = DELMODE_RESTOFCONTENT;
694                         break;
695                     default: break;
696                     }
697 
698                     mpImpl->mpTextEngine->UndoActionStart();
699                     if(mpImpl->mbSupportProtectAttribute)
700                     {
701                         //expand selection to include all protected content - if there is any
702                         const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
703                                     TextPaM(mpImpl->maSelection.GetStart().GetPara(),
704                                     mpImpl->maSelection.GetStart().GetIndex()),
705                                     TEXTATTR_PROTECTED );
706                         const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
707                                     TextPaM(mpImpl->maSelection.GetEnd().GetPara(),
708                                     mpImpl->maSelection.GetEnd().GetIndex()),
709                                     TEXTATTR_PROTECTED );
710                         if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex())
711                         {
712                             mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart();
713                         }
714                         if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex())
715                         {
716                             mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd();
717                         }
718                     }
719                     aCurSel = ImpDelete( nDel, nMode );
720                     mpImpl->mpTextEngine->UndoActionEnd();
721                     bModified = sal_True;
722                     bAllowIdle = sal_False;
723                 }
724                 else
725                     bDone = sal_False;
726             }
727             break;
728             case KEY_TAB:
729             {
730                 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() &&
731                         !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() &&
732                         ImplCheckTextLen( 'x' ) )
733                 {
734                     aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() );
735                     bModified = sal_True;
736                 }
737                 else
738                     bDone = sal_False;
739             }
740             break;
741             case KEY_RETURN:
742             {
743                 // Shift-RETURN darf nicht geschluckt werden, weil dann keine
744                 // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich.
745                 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() &&
746                         !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( 'x' ) )
747                 {
748                     mpImpl->mpTextEngine->UndoActionStart();
749                     aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel );
750                     if ( mpImpl->mbAutoIndent )
751                     {
752                         TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 );
753                         sal_uInt16 n = 0;
754                         while ( ( n < pPrev->GetText().Len() ) && (
755                                     ( pPrev->GetText().GetChar( n ) == ' ' ) ||
756                                     ( pPrev->GetText().GetChar( n ) == '\t' ) ) )
757                         {
758                             n++;
759                         }
760                         if ( n )
761                             aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) );
762                     }
763                     mpImpl->mpTextEngine->UndoActionEnd();
764                     bModified = sal_True;
765                 }
766                 else
767                     bDone = sal_False;
768             }
769             break;
770             case KEY_INSERT:
771             {
772                 if ( !mpImpl->mbReadOnly )
773                     SetInsertMode( !IsInsertMode() );
774             }
775             break;
776             default:
777             {
778                 if ( TextEngine::IsSimpleCharInput( rKeyEvent ) )
779                 {
780                     xub_Unicode nCharCode = rKeyEvent.GetCharCode();
781                     if ( !mpImpl->mbReadOnly && ImplCheckTextLen( nCharCode ) )    // sonst trotzdem das Zeichen schlucken...
782                     {
783                         aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True );
784                         bModified = sal_True;
785                     }
786                 }
787                 else
788                     bDone = sal_False;
789             }
790         }
791     }
792 
793     if ( aCurSel != aOldSel )   // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that!
794         ImpSetSelection( aCurSel );
795 
796     mpImpl->mpTextEngine->UpdateSelections();
797 
798     if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) )
799         mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
800 
801     if ( bModified )
802     {
803         // Idle-Formatter nur, wenn AnyInput.
804         if ( bAllowIdle && Application::AnyInput( INPUT_KEYBOARD) )
805             mpImpl->mpTextEngine->IdleFormatAndUpdate( this );
806         else
807             mpImpl->mpTextEngine->FormatAndUpdate( this);
808     }
809     else if ( bMoved )
810     {
811         // Selection wird jetzt gezielt in ImpMoveCursor gemalt.
812         ImpShowCursor( mpImpl->mbAutoScroll, sal_True, bEndKey );
813     }
814 
815     if ( mpImpl->mpTextEngine->IsModified() )
816         mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
817     else if ( bWasModified )
818         mpImpl->mpTextEngine->SetModified( sal_True );
819 
820     return bDone;
821 }
822 
823 void TextView::MouseButtonUp( const MouseEvent& rMouseEvent )
824 {
825     mpImpl->mbClickedInSelection = sal_False;
826     mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
827     mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent );
828     if ( rMouseEvent.IsMiddle() && !IsReadOnly() &&
829          ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
830     {
831         uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
832         Paste( aSelection );
833         if ( mpImpl->mpTextEngine->IsModified() )
834             mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
835     }
836     else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() )
837     {
838         uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
839         Copy( aSelection );
840     }
841 }
842 
843 void TextView::MouseButtonDown( const MouseEvent& rMouseEvent )
844 {
845     mpImpl->mpTextEngine->CheckIdleFormatter();    // Falls schnelles Tippen und MouseButtonDown
846     mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
847     mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
848 
849     mpImpl->mpTextEngine->SetActiveView( this );
850 
851     mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent );
852 
853     // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed'
854     // notification. The appropriate handler could change the current selection,
855     // which is the case in the MailMerge address block control. To enable select'n'drag
856     // we need to reevaluate the selection after the notification has been fired.
857     mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
858 
859     // Sonderbehandlungen
860     if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) )
861     {
862         if ( rMouseEvent.IsMod2() )
863         {
864             HideSelection();
865             ImpSetSelection( mpImpl->maSelection.GetEnd() );
866             SetCursorAtPoint( rMouseEvent.GetPosPixel() );  // Wird von SelectionEngine bei MOD2 nicht gesetzt
867         }
868 
869         if ( rMouseEvent.GetClicks() == 2 )
870         {
871             // Wort selektieren
872             if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) )
873             {
874                 HideSelection();
875                 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject(  mpImpl->maSelection.GetEnd().GetPara() );
876                 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
877                 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
878                 TextSelection aNewSel( mpImpl->maSelection );
879                 aNewSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos;
880                 aNewSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos;
881                 if(mpImpl->mbSupportProtectAttribute)
882                 {
883                     //expand selection to include all protected content - if there is any
884                     const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
885                                 TextPaM(aNewSel.GetStart().GetPara(),
886                                 (sal_uInt16)aBoundary.startPos),
887                                 TEXTATTR_PROTECTED );
888                     const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
889                                 TextPaM(aNewSel.GetEnd().GetPara(),
890                                 (sal_uInt16)aBoundary.endPos),
891                                 TEXTATTR_PROTECTED );
892                     if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex())
893                     {
894                         aNewSel.GetStart().GetIndex() = pStartAttr->GetStart();
895                     }
896                     if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex())
897                     {
898                         aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd();
899                     }
900                 }
901                 ImpSetSelection( aNewSel );
902                 ShowSelection();
903                 ShowCursor( sal_True, sal_True );
904             }
905         }
906         else if ( rMouseEvent.GetClicks() == 3 )
907         {
908             // Absatz selektieren
909             if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) )
910             {
911                 HideSelection();
912                 TextSelection aNewSel( mpImpl->maSelection );
913                 aNewSel.GetStart().GetIndex() = 0;
914                 aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() )->GetText().Len();
915                 ImpSetSelection( aNewSel );
916                 ShowSelection();
917                 ShowCursor( sal_True, sal_True );
918             }
919         }
920     }
921 }
922 
923 
924 void TextView::MouseMove( const MouseEvent& rMouseEvent )
925 {
926     mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
927     mpImpl->mpSelEngine->SelMouseMove( rMouseEvent );
928 }
929 
930 void TextView::Command( const CommandEvent& rCEvt )
931 {
932     mpImpl->mpTextEngine->CheckIdleFormatter();    // Falls schnelles Tippen und MouseButtonDown
933     mpImpl->mpTextEngine->SetActiveView( this );
934 
935     if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
936     {
937         DeleteSelected();
938         delete mpImpl->mpTextEngine->mpIMEInfos;
939         TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( GetSelection().GetEnd().GetPara() );
940         mpImpl->mpTextEngine->mpIMEInfos = new TEIMEInfos( GetSelection().GetEnd(), pNode->GetText().Copy( GetSelection().GetEnd().GetIndex() ) );
941         mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
942     }
943     else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
944     {
945         DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" );
946         if( mpImpl->mpTextEngine->mpIMEInfos )
947         {
948             TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() );
949             pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 );
950 
951             sal_Bool bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite;
952 
953             delete mpImpl->mpTextEngine->mpIMEInfos;
954             mpImpl->mpTextEngine->mpIMEInfos = NULL;
955 
956             mpImpl->mpTextEngine->FormatAndUpdate( this );
957 
958             SetInsertMode( bInsertMode );
959 
960             if ( mpImpl->mpTextEngine->IsModified() )
961                 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
962         }
963     }
964     else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
965     {
966         DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" );
967         if( mpImpl->mpTextEngine->mpIMEInfos )
968         {
969             const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
970 
971             if ( !pData->IsOnlyCursorChanged() )
972             {
973                 TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos );
974                 aSelect.GetEnd().GetIndex() = aSelect.GetEnd().GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen;
975                 aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect );
976                 aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() );
977 
978                 if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite )
979                 {
980                     sal_uInt16 nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen;
981                     sal_uInt16 nNewIMETextLen = pData->GetText().Len();
982 
983                     if ( ( nOldIMETextLen > nNewIMETextLen ) &&
984                          ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
985                     {
986                         // restore old characters
987                         sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen;
988                         TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos );
989                         aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen;
990                         mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) );
991                     }
992                     else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
993                               ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
994                     {
995                         // overwrite
996                         sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen;
997                         if ( ( nOldIMETextLen + nOverwrite ) > mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() )
998                             nOverwrite = mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen;
999                         DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" );
1000                         TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos );
1001                         aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen;
1002                         TextSelection aSel( aPaM );
1003                         aSel.GetEnd().GetIndex() =
1004                             aSel.GetEnd().GetIndex() + nOverwrite;
1005                         mpImpl->mpTextEngine->ImpDeleteText( aSel );
1006                     }
1007                 }
1008 
1009                 if ( pData->GetTextAttr() )
1010                 {
1011                     mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
1012                     mpImpl->mpTextEngine->mpIMEInfos->bCursor = pData->IsCursorVisible();
1013                 }
1014                 else
1015                 {
1016                     mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs();
1017                 }
1018 
1019                 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() );
1020                 pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 );
1021                 mpImpl->mpTextEngine->FormatAndUpdate( this );
1022             }
1023 
1024             TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() );
1025             SetSelection( aNewSel );
1026             SetInsertMode( !pData->IsCursorOverwrite() );
1027 
1028             if ( pData->IsCursorVisible() )
1029                 ShowCursor();
1030             else
1031                 HideCursor();
1032         }
1033     }
1034     else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
1035     {
1036         if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen )
1037         {
1038             TextPaM aPaM( GetSelection().GetEnd() );
1039             Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM );
1040 
1041             sal_uInt16 nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen;
1042 
1043             if ( !mpImpl->mpTextEngine->IsFormatted() )
1044                 mpImpl->mpTextEngine->FormatDoc();
1045 
1046             TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1047             sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True );
1048             TextLine* pLine = pParaPortion->GetLines().GetObject( nLine );
1049             if ( pLine && ( nInputEnd > pLine->GetEnd() ) )
1050                 nInputEnd = pLine->GetEnd();
1051             Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) );
1052 
1053             long nWidth = aR2.Left()-aR1.Right();
1054             aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() );
1055             GetWindow()->SetCursorRect( &aR1, nWidth );
1056         }
1057         else
1058         {
1059             GetWindow()->SetCursorRect();
1060         }
1061     }
1062     else
1063     {
1064         mpImpl->mpSelEngine->Command( rCEvt );
1065     }
1066 }
1067 
1068 void TextView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor )
1069 {
1070     // Die Einstellung hat mehr Gewicht:
1071     if ( !mpImpl->mbAutoScroll )
1072         bGotoCursor = sal_False;
1073     ImpShowCursor( bGotoCursor, bForceVisCursor, sal_False );
1074 }
1075 
1076 void TextView::HideCursor()
1077 {
1078     mpImpl->mpCursor->Hide();
1079 }
1080 
1081 void TextView::Scroll( long ndX, long ndY )
1082 {
1083     DBG_ASSERT( mpImpl->mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" );
1084 
1085     if ( !ndX && !ndY )
1086         return;
1087 
1088     Point aNewStartPos( mpImpl->maStartDocPos );
1089 
1090     // Vertical:
1091     aNewStartPos.Y() -= ndY;
1092     if ( aNewStartPos.Y() < 0 )
1093         aNewStartPos.Y() = 0;
1094 
1095     // Horizontal:
1096     aNewStartPos.X() -= ndX;
1097     if ( aNewStartPos.X() < 0 )
1098         aNewStartPos.X() = 0;
1099 
1100     long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X();
1101     long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y();
1102 
1103     if ( nDiffX || nDiffY )
1104     {
1105         sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible();
1106         mpImpl->mpCursor->Hide();
1107         mpImpl->mpWindow->Update();
1108         mpImpl->maStartDocPos = aNewStartPos;
1109 
1110         if ( mpImpl->mpTextEngine->IsRightToLeft() )
1111             nDiffX = -nDiffX;
1112         mpImpl->mpWindow->Scroll( nDiffX, nDiffY );
1113         mpImpl->mpWindow->Update();
1114         mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) );
1115         if ( bVisCursor && !mpImpl->mbReadOnly )
1116             mpImpl->mpCursor->Show();
1117     }
1118 
1119     mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) );
1120 }
1121 
1122 void TextView::Undo()
1123 {
1124     mpImpl->mpTextEngine->SetActiveView( this );
1125     mpImpl->mpTextEngine->GetUndoManager().Undo();
1126 }
1127 
1128 void TextView::Redo()
1129 {
1130     mpImpl->mpTextEngine->SetActiveView( this );
1131     mpImpl->mpTextEngine->GetUndoManager().Redo();
1132 }
1133 
1134 void TextView::Cut()
1135 {
1136     mpImpl->mpTextEngine->UndoActionStart();
1137     Copy();
1138     DeleteSelected();
1139     mpImpl->mpTextEngine->UndoActionEnd();
1140 }
1141 
1142 void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1143 {
1144     if ( rxClipboard.is() )
1145     {
1146         TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
1147 
1148         if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) )  // Dann auch als HTML
1149             mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True );
1150 
1151         const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1152 
1153         try
1154         {
1155             rxClipboard->setContents( pDataObj, NULL );
1156 
1157             uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
1158             if( xFlushableClipboard.is() )
1159                 xFlushableClipboard->flushClipboard();
1160         }
1161         catch( const ::com::sun::star::uno::Exception& )
1162         {
1163         }
1164 
1165         Application::AcquireSolarMutex( nRef );
1166     }
1167 }
1168 
1169 void TextView::Copy()
1170 {
1171     uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard());
1172     Copy( aClipboard );
1173 }
1174 
1175 void TextView::Paste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1176 {
1177     if ( rxClipboard.is() )
1178     {
1179         uno::Reference< datatransfer::XTransferable > xDataObj;
1180 
1181         const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1182 
1183         try
1184         {
1185             xDataObj = rxClipboard->getContents();
1186         }
1187         catch( const ::com::sun::star::uno::Exception& )
1188         {
1189         }
1190 
1191         Application::AcquireSolarMutex( nRef );
1192 
1193         if ( xDataObj.is() )
1194         {
1195             datatransfer::DataFlavor aFlavor;
1196             SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
1197             if ( xDataObj->isDataFlavorSupported( aFlavor ) )
1198             {
1199                 try
1200                 {
1201                     uno::Any aData = xDataObj->getTransferData( aFlavor );
1202                     ::rtl::OUString aText;
1203                     aData >>= aText;
1204                     bool bWasTruncated = false;
1205                     if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 )
1206                         bWasTruncated = ImplTruncateNewText( aText );
1207                     InsertNewText( aText, sal_False );
1208                     mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
1209 
1210                     if( bWasTruncated )
1211                         Edit::ShowTruncationWarning( mpImpl->mpWindow );
1212                 }
1213                 catch( const ::com::sun::star::datatransfer::UnsupportedFlavorException& )
1214                 {
1215                 }
1216             }
1217         }
1218     }
1219 }
1220 
1221 void TextView::Paste()
1222 {
1223     uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard());
1224     Paste( aClipboard );
1225 }
1226 
1227 String TextView::GetSelected()
1228 {
1229     return GetSelected( GetSystemLineEnd() );
1230 }
1231 
1232 String TextView::GetSelected( LineEnd aSeparator )
1233 {
1234     return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator );
1235 }
1236 
1237 void TextView::SetInsertMode( sal_Bool bInsert )
1238 {
1239     if ( mpImpl->mbInsertMode != bInsert )
1240     {
1241         mpImpl->mbInsertMode = bInsert;
1242         ShowCursor( mpImpl->mbAutoScroll, sal_False );
1243     }
1244 }
1245 
1246 void TextView::SetReadOnly( sal_Bool bReadOnly )
1247 {
1248     if ( mpImpl->mbReadOnly != bReadOnly )
1249     {
1250         mpImpl->mbReadOnly = bReadOnly;
1251         if ( !mpImpl->mbReadOnly )
1252             ShowCursor( mpImpl->mbAutoScroll, sal_False );
1253         else
1254             HideCursor();
1255 
1256         GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
1257     }
1258 }
1259 
1260 TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent )
1261 {
1262     // Eigentlich nur bei Up/Down noetig, aber was solls.
1263     mpImpl->mpTextEngine->CheckIdleFormatter();
1264 
1265     TextPaM aPaM( mpImpl->maSelection.GetEnd() );
1266     TextPaM aOldEnd( aPaM );
1267 
1268     TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom;
1269     if ( mpImpl->mpTextEngine->IsRightToLeft() )
1270         eTextDirection = TextDirectionality_RightToLeft_TopToBottom;
1271 
1272     KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection );
1273 
1274     sal_Bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? sal_True : sal_False;
1275     sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode();
1276 
1277     bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift();
1278     switch ( nCode )
1279     {
1280         case KEY_UP:        aPaM = CursorUp( aPaM );
1281                             break;
1282         case KEY_DOWN:      aPaM = CursorDown( aPaM );
1283                             break;
1284         case KEY_HOME:      aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM );
1285                             break;
1286         case KEY_END:       aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM );
1287                             break;
1288         case KEY_PAGEUP:    aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM );
1289                             break;
1290         case KEY_PAGEDOWN:  aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM );
1291                             break;
1292         case KEY_LEFT:      aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
1293                             break;
1294         case KEY_RIGHT:     aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
1295                             break;
1296         case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1297                             bSelect = true; // fallthrough intentional
1298         case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1299                             aPaM = CursorWordRight( aPaM );
1300                             break;
1301         case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1302                             bSelect = true; // fallthrough intentional
1303         case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1304                             aPaM = CursorWordLeft( aPaM );
1305                             break;
1306         case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1307                             bSelect = true; // fallthrough intentional
1308         case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1309                             aPaM = CursorStartOfLine( aPaM );
1310                             break;
1311         case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1312                             bSelect = true; // fallthrough intentional
1313         case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1314                             aPaM = CursorEndOfLine( aPaM );
1315                             break;
1316         case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1317                             bSelect = true; // falltthrough intentional
1318         case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1319                             aPaM = CursorStartOfParagraph( aPaM );
1320                             break;
1321         case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1322                             bSelect = true; // falltthrough intentional
1323         case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1324                             aPaM = CursorEndOfParagraph( aPaM );
1325                             break;
1326         case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1327                             bSelect = true; // falltthrough intentional
1328         case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1329                             aPaM = CursorStartOfDoc();
1330                             break;
1331         case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1332                             bSelect = true; // falltthrough intentional
1333         case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1334                             aPaM = CursorEndOfDoc();
1335                             break;
1336     }
1337 
1338     // Bewirkt evtl. ein CreateAnchor oder Deselection all
1339     mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
1340 
1341     if ( aOldEnd != aPaM )
1342     {
1343         mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() );
1344 
1345 
1346         TextSelection aOldSelection( mpImpl->maSelection );
1347         TextSelection aNewSelection( mpImpl->maSelection );
1348         aNewSelection.GetEnd() = aPaM;
1349         if ( bSelect )
1350         {
1351             // Dann wird die Selektion erweitert...
1352             ImpSetSelection( aNewSelection );
1353             ShowSelection( TextSelection( aOldEnd, aPaM ) );
1354         }
1355         else
1356         {
1357             aNewSelection.GetStart() = aPaM;
1358             ImpSetSelection( aNewSelection );
1359         }
1360     }
1361 
1362     return mpImpl->maSelection;
1363 }
1364 
1365 void TextView::InsertText( const XubString& rStr, sal_Bool bSelect )
1366 {
1367     InsertNewText( rStr, bSelect );
1368 }
1369 
1370 void TextView::InsertNewText( const rtl::OUString& rStr, sal_Bool bSelect )
1371 {
1372 //  HideSelection();
1373     mpImpl->mpTextEngine->UndoActionStart();
1374 
1375     /* #i87633#
1376     break inserted text into chunks that fit into the underlying String
1377     based API (which has a maximum length of 65534 elements
1378 
1379     note: this will of course still cause problems for lines longer than those
1380     65534 elements, but those cases will hopefully be few.
1381     In the long run someone should switch the TextEngine to OUString instead of String
1382     */
1383     sal_Int32 nLen = rStr.getLength();
1384     sal_Int32 nPos = 0;
1385     while( nLen )
1386     {
1387         sal_Int32 nChunkLen = nLen > 65534 ? 65534 : nLen;
1388         String aChunk( rStr.copy( nPos, nChunkLen ) );
1389 
1390         TextSelection aNewSel( mpImpl->maSelection );
1391 
1392         TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, aChunk );
1393 
1394         if ( bSelect )
1395         {
1396             aNewSel.Justify();
1397             aNewSel.GetEnd() = aPaM;
1398         }
1399         else
1400         {
1401             aNewSel = aPaM;
1402         }
1403 
1404         ImpSetSelection( aNewSel );
1405         nLen -= nChunkLen;
1406         nPos += nChunkLen;
1407     }
1408     mpImpl->mpTextEngine->UndoActionEnd();
1409 
1410     mpImpl->mpTextEngine->FormatAndUpdate( this );
1411 }
1412 
1413 /*
1414 void TextView::InsertText( const XubString& rStr, sal_Bool bSelect )
1415 {
1416 //  HideSelection();
1417 
1418     TextSelection aNewSel( mpImpl->maSelection );
1419 
1420     mpImpl->mpTextEngine->UndoActionStart();
1421     TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, rStr );
1422     mpImpl->mpTextEngine->UndoActionEnd();
1423 
1424     if ( bSelect )
1425     {
1426         aNewSel.Justify();
1427         aNewSel.GetEnd() = aPaM;
1428     }
1429     else
1430     {
1431         aNewSel = aPaM;
1432     }
1433 
1434     ImpSetSelection( aNewSel );
1435 
1436     mpImpl->mpTextEngine->FormatAndUpdate( this );
1437 }
1438 */
1439 
1440 // OLD
1441 TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_Bool bWordMode )
1442 {
1443     return bWordMode ? CursorWordLeft( rPaM ) : CursorLeft( rPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
1444 
1445     // Remove (sal_uInt16) typecasts in this file when removing this method!
1446 }
1447 
1448 // OLD
1449 TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_Bool bWordMode )
1450 {
1451     return bWordMode ? CursorWordRight( rPaM ) : CursorRight( rPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
1452 
1453     // Remove (sal_uInt16) typecasts in this file when removing this method!
1454 }
1455 
1456 TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode )
1457 {
1458     TextPaM aPaM( rPaM );
1459 
1460     if ( aPaM.GetIndex() )
1461     {
1462         TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1463         uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1464         sal_Int32 nCount = 1;
1465         aPaM.GetIndex() = (sal_uInt16)xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount );
1466     }
1467     else if ( aPaM.GetPara() )
1468     {
1469         aPaM.GetPara()--;
1470         TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1471         aPaM.GetIndex() = pNode->GetText().Len();
1472     }
1473     return aPaM;
1474 }
1475 
1476 TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode )
1477 {
1478     TextPaM aPaM( rPaM );
1479 
1480     TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1481     if ( aPaM.GetIndex() < pNode->GetText().Len() )
1482     {
1483         uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1484         sal_Int32 nCount = 1;
1485         aPaM.GetIndex() = (sal_uInt16)xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount );
1486     }
1487     else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
1488     {
1489         aPaM.GetPara()++;
1490         aPaM.GetIndex() = 0;
1491     }
1492 
1493     return aPaM;
1494 }
1495 
1496 
1497 TextPaM TextView::CursorWordLeft( const TextPaM& rPaM )
1498 {
1499     TextPaM aPaM( rPaM );
1500 
1501     if ( aPaM.GetIndex() )
1502     {
1503         TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1504         uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1505         i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1506         if ( aBoundary.startPos >= rPaM.GetIndex() )
1507             aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1508         aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? (sal_uInt16)aBoundary.startPos : 0;
1509     }
1510     else if ( aPaM.GetPara() )
1511     {
1512         aPaM.GetPara()--;
1513         TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1514         aPaM.GetIndex() = pNode->GetText().Len();
1515     }
1516     return aPaM;
1517 }
1518 
1519 
1520 TextPaM TextView::CursorWordRight( const TextPaM& rPaM )
1521 {
1522     TextPaM aPaM( rPaM );
1523 
1524     TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1525     if ( aPaM.GetIndex() < pNode->GetText().Len() )
1526     {
1527         uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1528         i18n::Boundary aBoundary = xBI->nextWord(  pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1529         aPaM.GetIndex() = (sal_uInt16)aBoundary.startPos;
1530     }
1531     else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
1532     {
1533         aPaM.GetPara()++;
1534         aPaM.GetIndex() = 0;
1535     }
1536 
1537     return aPaM;
1538 }
1539 
1540 TextPaM TextView::ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode )
1541 {
1542     if ( mpImpl->maSelection.HasRange() )  // dann nur Sel. loeschen
1543         return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
1544 
1545     TextPaM aStartPaM = mpImpl->maSelection.GetStart();
1546     TextPaM aEndPaM = aStartPaM;
1547     if ( nMode == DEL_LEFT )
1548     {
1549         if ( nDelMode == DELMODE_SIMPLE )
1550         {
1551             aEndPaM = CursorLeft( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER );
1552         }
1553         else if ( nDelMode == DELMODE_RESTOFWORD )
1554         {
1555             TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject(  aEndPaM.GetPara() );
1556             uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1557             i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1558             if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() )
1559                 aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1560             // #i63506# startPos is -1 when the paragraph starts with a tab
1561             aEndPaM.GetIndex() = (aBoundary.startPos >= 0) ? (sal_uInt16)aBoundary.startPos : 0;
1562         }
1563         else    // DELMODE_RESTOFCONTENT
1564         {
1565             if ( aEndPaM.GetIndex() != 0 )
1566                 aEndPaM.GetIndex() = 0;
1567             else if ( aEndPaM.GetPara() )
1568             {
1569                 // Absatz davor
1570                 aEndPaM.GetPara()--;
1571                 aEndPaM.GetIndex() = 0;
1572             }
1573         }
1574     }
1575     else
1576     {
1577         if ( nDelMode == DELMODE_SIMPLE )
1578         {
1579             aEndPaM = CursorRight( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
1580         }
1581         else if ( nDelMode == DELMODE_RESTOFWORD )
1582         {
1583             TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject(  aEndPaM.GetPara() );
1584             uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1585             i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1586             aEndPaM.GetIndex() = (sal_uInt16)aBoundary.startPos;
1587         }
1588         else    // DELMODE_RESTOFCONTENT
1589         {
1590             TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
1591             if ( aEndPaM.GetIndex() < pNode->GetText().Len() )
1592                 aEndPaM.GetIndex() = pNode->GetText().Len();
1593             else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) )
1594             {
1595                 // Absatz danach
1596                 aEndPaM.GetPara()++;
1597                 TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
1598                 aEndPaM.GetIndex() = pNextNode->GetText().Len();
1599             }
1600         }
1601     }
1602 
1603     return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) );
1604 }
1605 
1606 
1607 
1608 TextPaM TextView::CursorUp( const TextPaM& rPaM )
1609 {
1610     TextPaM aPaM( rPaM );
1611 
1612     long nX;
1613     if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW )
1614     {
1615         nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left();
1616         mpImpl->mnTravelXPos = (sal_uInt16)nX+1;
1617     }
1618     else
1619         nX = mpImpl->mnTravelXPos;
1620 
1621     TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1622     sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False );
1623     if ( nLine )    // gleicher Absatz
1624     {
1625         sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX );
1626         aPaM.GetIndex() = nCharPos;
1627         // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das
1628         // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang
1629         // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor
1630         TextLine* pLine = pPPortion->GetLines().GetObject( nLine - 1 );
1631         if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) )
1632             aPaM.GetIndex()--;
1633     }
1634     else if ( rPaM.GetPara() )  // vorheriger Absatz
1635     {
1636         aPaM.GetPara()--;
1637         pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1638         sal_uInt16 nL = pPPortion->GetLines().Count() - 1;
1639         sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 );
1640         aPaM.GetIndex() = nCharPos;
1641     }
1642 
1643     return aPaM;
1644 }
1645 
1646 TextPaM TextView::CursorDown( const TextPaM& rPaM )
1647 {
1648     TextPaM aPaM( rPaM );
1649 
1650     long nX;
1651     if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW )
1652     {
1653         nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left();
1654         mpImpl->mnTravelXPos = (sal_uInt16)nX+1;
1655     }
1656     else
1657         nX = mpImpl->mnTravelXPos;
1658 
1659     TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1660     sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False );
1661     if ( nLine < ( pPPortion->GetLines().Count() - 1 ) )
1662     {
1663         sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX );
1664         aPaM.GetIndex() = nCharPos;
1665 
1666         // Sonderbehandlung siehe CursorUp...
1667         TextLine* pLine = pPPortion->GetLines().GetObject( nLine + 1 );
1668         if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() )
1669             aPaM.GetIndex()--;
1670     }
1671     else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) )   // naechster Absatz
1672     {
1673         aPaM.GetPara()++;
1674         pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1675         sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 );
1676         aPaM.GetIndex() = nCharPos;
1677         TextLine* pLine = pPPortion->GetLines().GetObject( 0 );
1678         if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().Count() > 1 ) )
1679             aPaM.GetIndex()--;
1680     }
1681 
1682     return aPaM;
1683 }
1684 
1685 TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM )
1686 {
1687     TextPaM aPaM( rPaM );
1688 
1689     TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1690     sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
1691     TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
1692     aPaM.GetIndex() = pLine->GetStart();
1693 
1694     return aPaM;
1695 }
1696 
1697 TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM )
1698 {
1699     TextPaM aPaM( rPaM );
1700 
1701     TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1702     sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
1703     TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
1704     aPaM.GetIndex() = pLine->GetEnd();
1705 
1706     if ( pLine->GetEnd() > pLine->GetStart() )  // Leerzeile
1707     {
1708         xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((sal_uInt16)(aPaM.GetIndex()-1) );
1709         if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().Len() ) )
1710         {
1711             // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn,
1712             // davor zu stehen, da der Anwender hinter das Wort will.
1713             // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End!
1714             aPaM.GetIndex()--;
1715         }
1716     }
1717     return aPaM;
1718 }
1719 
1720 TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM )
1721 {
1722     TextPaM aPaM( rPaM );
1723     aPaM.GetIndex() = 0;
1724     return aPaM;
1725 }
1726 
1727 TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM )
1728 {
1729     TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( rPaM.GetPara() );
1730     TextPaM aPaM( rPaM );
1731     aPaM.GetIndex() = pNode->GetText().Len();
1732     return aPaM;
1733 }
1734 
1735 TextPaM TextView::CursorStartOfDoc()
1736 {
1737     TextPaM aPaM( 0, 0 );
1738     return aPaM;
1739 }
1740 
1741 TextPaM TextView::CursorEndOfDoc()
1742 {
1743     sal_uLong nNode = mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1;
1744     TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( nNode );
1745     TextPaM aPaM( nNode, pNode->GetText().Len() );
1746     return aPaM;
1747 }
1748 
1749 TextPaM TextView::PageUp( const TextPaM& rPaM )
1750 {
1751     Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM );
1752     Point aTopLeft = aRec.TopLeft();
1753     aTopLeft.Y() -= mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10;
1754     aTopLeft.X() += 1;
1755     if ( aTopLeft.Y() < 0 )
1756         aTopLeft.Y() = 0;
1757 
1758     TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft );
1759     return aPaM;
1760 }
1761 
1762 TextPaM TextView::PageDown( const TextPaM& rPaM )
1763 {
1764     Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM );
1765     Point aBottomRight = aRec.BottomRight();
1766     aBottomRight.Y() += mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10;
1767     aBottomRight.X() += 1;
1768     long nHeight = mpImpl->mpTextEngine->GetTextHeight();
1769     if ( aBottomRight.Y() > nHeight )
1770         aBottomRight.Y() = nHeight-1;
1771 
1772     TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight );
1773     return aPaM;
1774 }
1775 
1776 void TextView::ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bSpecial )
1777 {
1778     if ( mpImpl->mpTextEngine->IsFormatting() )
1779         return;
1780     if ( mpImpl->mpTextEngine->GetUpdateMode() == sal_False )
1781         return;
1782     if ( mpImpl->mpTextEngine->IsInUndo() )
1783         return;
1784 
1785     mpImpl->mpTextEngine->CheckIdleFormatter();
1786     if ( !mpImpl->mpTextEngine->IsFormatted() )
1787         mpImpl->mpTextEngine->FormatAndUpdate( this );
1788 
1789 
1790     TextPaM aPaM( mpImpl->maSelection.GetEnd() );
1791     Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial );
1792 
1793     // Remember that we placed the cursor behind the last character of a line
1794     mpImpl->mbCursorAtEndOfLine = false;
1795     if( bSpecial )
1796     {
1797         TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1798         mpImpl->mbCursorAtEndOfLine =
1799             pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
1800     }
1801 
1802     if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() )
1803     {
1804         TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1805         if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) )
1806         {
1807             // If we are behind a portion, and the next portion has other direction, we must change position...
1808             aEditCursor.Left() = aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aPaM, sal_False, sal_True ).Left();
1809 
1810             TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1811 
1812             sal_uInt16 nTextPortionStart = 0;
1813             sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, sal_True );
1814             TETextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion );
1815             if ( pTextPortion->GetKind() == PORTIONKIND_TAB )
1816             {
1817                 if ( mpImpl->mpTextEngine->IsRightToLeft() )
1818                 {
1819 
1820                 }
1821                 aEditCursor.Right() += pTextPortion->GetWidth();
1822             }
1823             else
1824             {
1825                 TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
1826                 aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, sal_True ).Left();
1827             }
1828         }
1829     }
1830 
1831     Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel();
1832     if ( aEditCursor.GetHeight() > aOutSz.Height() )
1833         aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1;
1834 
1835     aEditCursor.Left() -= 1;
1836 
1837     if ( bGotoCursor
1838         // #i81283# protext maStartDocPos against initialization problems
1839         && aOutSz.Width() && aOutSz.Height()
1840     )
1841     {
1842         long nVisStartY = mpImpl->maStartDocPos.Y();
1843         long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height();
1844         long nVisStartX = mpImpl->maStartDocPos.X();
1845         long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width();
1846         long nMoreX = aOutSz.Width() / 4;
1847 
1848         Point aNewStartPos( mpImpl->maStartDocPos );
1849 
1850         if ( aEditCursor.Bottom() > nVisEndY )
1851         {
1852             aNewStartPos.Y() += ( aEditCursor.Bottom() - nVisEndY );
1853         }
1854         else if ( aEditCursor.Top() < nVisStartY )
1855         {
1856             aNewStartPos.Y() -= ( nVisStartY - aEditCursor.Top() );
1857         }
1858 
1859         if ( aEditCursor.Right() >= nVisEndX )
1860         {
1861             aNewStartPos.X() += ( aEditCursor.Right() - nVisEndX );
1862 
1863             // Darfs ein bischen mehr sein?
1864             aNewStartPos.X() += nMoreX;
1865         }
1866         else if ( aEditCursor.Left() <= nVisStartX )
1867         {
1868             aNewStartPos.X() -= ( nVisStartX - aEditCursor.Left() );
1869 
1870             // Darfs ein bischen mehr sein?
1871             aNewStartPos.X() -= nMoreX;
1872         }
1873 
1874         // X kann durch das 'bischen mehr' falsch sein:
1875 //      sal_uLong nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth();
1876 //      if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) )
1877 //          nMaxTextWidth = 0x7FFFFFFF;
1878 //      long nMaxX = (long)nMaxTextWidth - aOutSz.Width();
1879         long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width();
1880         if ( nMaxX < 0 )
1881             nMaxX = 0;
1882 
1883         if ( aNewStartPos.X() < 0 )
1884             aNewStartPos.X() = 0;
1885         else if ( aNewStartPos.X() > nMaxX )
1886             aNewStartPos.X() = nMaxX;
1887 
1888         // Y sollte nicht weiter unten als noetig liegen:
1889         long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height();
1890         if ( nYMax < 0 )
1891             nYMax = 0;
1892         if ( aNewStartPos.Y() > nYMax )
1893             aNewStartPos.Y() = nYMax;
1894 
1895         if ( aNewStartPos != mpImpl->maStartDocPos )
1896             Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) );
1897     }
1898 
1899     if ( aEditCursor.Right() < aEditCursor.Left() )
1900     {
1901         long n = aEditCursor.Left();
1902         aEditCursor.Left() = aEditCursor.Right();
1903         aEditCursor.Right() = n;
1904     }
1905 
1906     Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) );
1907     mpImpl->mpCursor->SetPos( aPoint );
1908     mpImpl->mpCursor->SetSize( aEditCursor.GetSize() );
1909     if ( bForceVisCursor && mpImpl->mbCursorEnabled )
1910         mpImpl->mpCursor->Show();
1911 }
1912 
1913 sal_Bool TextView::SetCursorAtPoint( const Point& rPosPixel )
1914 {
1915     mpImpl->mpTextEngine->CheckIdleFormatter();
1916 
1917     Point aDocPos = GetDocPos( rPosPixel );
1918 
1919     TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos );
1920 
1921     // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion
1922     TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM );
1923     TextSelection aNewSel( mpImpl->maSelection );
1924     aNewSel.GetEnd() = aPaM;
1925 
1926     if ( !mpImpl->mpSelEngine->HasAnchor() )
1927     {
1928         if ( mpImpl->maSelection.GetStart() != aPaM )
1929             mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() );
1930         aNewSel.GetStart() = aPaM;
1931         ImpSetSelection( aNewSel );
1932     }
1933     else
1934     {
1935         ImpSetSelection( aNewSel );
1936         ShowSelection( aTmpNewSel );
1937     }
1938 
1939     sal_Bool bForceCursor =  mpImpl->mpDDInfo ? sal_False : sal_True; // && !mbInSelection
1940     ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, sal_False );
1941     return sal_True;
1942 }
1943 
1944 sal_Bool TextView::IsSelectionAtPoint( const Point& rPosPixel )
1945 {
1946 //  if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection )
1947 //      return sal_False;
1948 
1949     Point aDocPos = GetDocPos( rPosPixel );
1950     TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos, sal_False );
1951     // Bei Hyperlinks D&D auch ohne Selektion starten.
1952     // BeginDrag wird aber nur gerufen, wenn IsSelectionAtPoint()
1953     // Problem: IsSelectionAtPoint wird bei Command() nicht gerufen,
1954     // wenn vorher im MBDown schon sal_False returnt wurde.
1955     return ( IsInSelection( aPaM ) ||
1956             ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) );
1957 }
1958 
1959 sal_Bool TextView::IsInSelection( const TextPaM& rPaM )
1960 {
1961     TextSelection aSel = mpImpl->maSelection;
1962     aSel.Justify();
1963 
1964     sal_uLong nStartNode = aSel.GetStart().GetPara();
1965     sal_uLong nEndNode = aSel.GetEnd().GetPara();
1966     sal_uLong nCurNode = rPaM.GetPara();
1967 
1968     if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) )
1969         return sal_True;
1970 
1971     if ( nStartNode == nEndNode )
1972     {
1973         if ( nCurNode == nStartNode )
1974             if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
1975                 return sal_True;
1976     }
1977     else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) )
1978         return sal_True;
1979     else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
1980         return sal_True;
1981 
1982     return sal_False;
1983 }
1984 
1985 void TextView::ImpHideDDCursor()
1986 {
1987     if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor )
1988     {
1989         mpImpl->mpDDInfo->maCursor.Hide();
1990         mpImpl->mpDDInfo->mbVisCursor = sal_False;
1991     }
1992 }
1993 
1994 void TextView::ImpShowDDCursor()
1995 {
1996     if ( !mpImpl->mpDDInfo->mbVisCursor )
1997     {
1998         Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, sal_True );
1999         aCursor.Right()++;
2000         aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) );
2001 
2002         mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow );
2003         mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() );
2004         mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() );
2005         mpImpl->mpDDInfo->maCursor.Show();
2006         mpImpl->mpDDInfo->mbVisCursor = sal_True;
2007     }
2008 }
2009 
2010 void TextView::SetPaintSelection( sal_Bool bPaint )
2011 {
2012     if ( bPaint != mpImpl->mbPaintSelection )
2013     {
2014         mpImpl->mbPaintSelection = bPaint;
2015         ShowSelection( mpImpl->maSelection );
2016     }
2017 }
2018 
2019 void TextView::SetHighlightSelection( sal_Bool bSelectByHighlight )
2020 {
2021     if ( bSelectByHighlight != mpImpl->mbHighlightSelection )
2022     {
2023         // Falls umschalten zwischendurch moeglich...
2024         mpImpl->mbHighlightSelection = bSelectByHighlight;
2025     }
2026 }
2027 
2028 sal_Bool TextView::Read( SvStream& rInput )
2029 {
2030     sal_Bool bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection );
2031     ShowCursor();
2032     return bDone;
2033 }
2034 
2035 sal_Bool TextView::Write( SvStream& rOutput )
2036 {
2037     return mpImpl->mpTextEngine->Read( rOutput, &mpImpl->maSelection );
2038 }
2039 
2040 bool TextView::ImplTruncateNewText( rtl::OUString& rNewText ) const
2041 {
2042     bool bTruncated = false;
2043 
2044     if( rNewText.getLength() > 65534 ) // limit to String API
2045     {
2046         rNewText = rNewText.copy( 0, 65534 );
2047         bTruncated = true;
2048     }
2049 
2050     sal_uLong nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen();
2051     // 0 means unlimited, there is just the String API limit handled above
2052     if( nMaxLen != 0 )
2053     {
2054         sal_uLong nCurLen = mpImpl->mpTextEngine->GetTextLen();
2055 
2056         sal_uInt32 nNewLen = rNewText.getLength();
2057         if ( nCurLen + nNewLen > nMaxLen )
2058         {
2059             // see how much text will be replaced
2060             sal_uLong nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection );
2061             if ( nCurLen + nNewLen - nSelLen > nMaxLen )
2062             {
2063                 sal_uInt32 nTruncatedLen = static_cast<sal_uInt32>(nMaxLen - (nCurLen - nSelLen));
2064                 rNewText = rNewText.copy( 0, nTruncatedLen );
2065                 bTruncated = true;
2066             }
2067         }
2068     }
2069     return bTruncated;
2070 }
2071 
2072 sal_Bool TextView::ImplCheckTextLen( const String& rNewText )
2073 {
2074     sal_Bool bOK = sal_True;
2075     if ( mpImpl->mpTextEngine->GetMaxTextLen() )
2076     {
2077         sal_uLong n = mpImpl->mpTextEngine->GetTextLen();
2078         n += rNewText.Len();
2079         if ( n > mpImpl->mpTextEngine->GetMaxTextLen() )
2080         {
2081             // nur dann noch ermitteln, wie viel Text geloescht wird
2082             n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection );
2083             if ( n > mpImpl->mpTextEngine->GetMaxTextLen() )
2084             {
2085                 // Beep hat hier eigentlich nichts verloren, sondern lieber ein Hdl,
2086                 // aber so funktioniert es wenigstens in ME, BasicIDE, SourceView
2087                 Sound::Beep();
2088                 bOK = sal_False;
2089             }
2090         }
2091     }
2092     return bOK;
2093 }
2094 
2095 void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
2096 {
2097     if ( mpImpl->mbClickedInSelection )
2098     {
2099         vos::OGuard aVclGuard( Application::GetSolarMutex() );
2100 
2101         DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" );
2102 
2103         delete mpImpl->mpDDInfo;
2104         mpImpl->mpDDInfo = new TextDDInfo;
2105         mpImpl->mpDDInfo->mbStarterOfDD = sal_True;
2106 
2107         TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
2108 
2109         if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) )  // Dann auch als HTML
2110             mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True );
2111 
2112 
2113         /*
2114         // D&D eines Hyperlinks.
2115         // Besser waere es im MBDown sich den MBDownPaM zu merken,
2116         // ist dann aber inkompatibel => spaeter mal umstellen.
2117         TextPaM aPaM( mpImpl->mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) );
2118         const TextCharAttrib* pAttr = mpImpl->mpTextEngine->FindCharAttrib( aPaM, TEXTATTR_HYPERLINK );
2119         if ( pAttr )
2120         {
2121             aSel = aPaM;
2122             aSel.GetStart().GetIndex() = pAttr->GetStart();
2123             aSel.GetEnd().GetIndex() = pAttr->GetEnd();
2124 
2125             const TextAttribHyperLink& rLink = (const TextAttribHyperLink&)pAttr->GetAttr();
2126             String aText( rLink.GetDescription() );
2127             if ( !aText.Len() )
2128                 aText = mpImpl->mpTextEngine->GetText( aSel );
2129             INetBookmark aBookmark( rLink.GetURL(), aText );
2130             aBookmark.CopyDragServer();
2131         }
2132         */
2133 
2134         mpImpl->mpCursor->Hide();
2135 
2136         sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
2137         if ( !IsReadOnly() )
2138             nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
2139         rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener );
2140     }
2141 }
2142 
2143 void TextView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& ) throw (::com::sun::star::uno::RuntimeException)
2144 {
2145     ImpHideDDCursor();
2146     delete mpImpl->mpDDInfo;
2147     mpImpl->mpDDInfo = NULL;
2148 }
2149 
2150 void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
2151 {
2152     vos::OGuard aVclGuard( Application::GetSolarMutex() );
2153 
2154     sal_Bool bChanges = sal_False;
2155     if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo )
2156     {
2157         ImpHideDDCursor();
2158 
2159         // Daten fuer das loeschen nach einem DROP_MOVE:
2160         TextSelection aPrevSel( mpImpl->maSelection );
2161         aPrevSel.Justify();
2162         sal_uLong nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount();
2163         sal_uInt16 nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() );
2164 
2165         sal_Bool bStarterOfDD = sal_False;
2166         for ( sal_uInt16 nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; )
2167             bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : sal_False;
2168 
2169         HideSelection();
2170         ImpSetSelection( mpImpl->mpDDInfo->maDropPos );
2171 
2172         mpImpl->mpTextEngine->UndoActionStart();
2173 
2174         String aText;
2175         uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
2176         if ( xDataObj.is() )
2177         {
2178             datatransfer::DataFlavor aFlavor;
2179             SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
2180             if ( xDataObj->isDataFlavorSupported( aFlavor ) )
2181             {
2182                 uno::Any aData = xDataObj->getTransferData( aFlavor );
2183                 ::rtl::OUString aOUString;
2184                 aData >>= aOUString;
2185                 aText = aOUString;
2186                 aText.ConvertLineEnd( LINEEND_LF );
2187             }
2188         }
2189 
2190         if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) )
2191             aText.Erase( aText.Len()-1 );
2192 
2193         TextPaM aTempStart = mpImpl->maSelection.GetStart();
2194         if ( ImplCheckTextLen( aText ) )
2195             ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) );
2196         if(mpImpl->mbSupportProtectAttribute)
2197         {
2198             mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(),
2199                 aTempStart.GetPara(),
2200                 aTempStart.GetIndex(),
2201                 mpImpl->maSelection.GetEnd().GetIndex(), sal_False );
2202         }
2203 
2204         if ( aPrevSel.HasRange() &&
2205                 !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element
2206                 (( rDTDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) )
2207         {
2208             // ggf. Selection anpasssen:
2209             if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) ||
2210                  ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
2211                         && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) )
2212             {
2213                 sal_uLong nNewParasBeforeSelection =
2214                     mpImpl->mpTextEngine->GetParagraphCount() -    nPrevParaCount;
2215 
2216                 aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection;
2217                 aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection;
2218 
2219                 if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
2220                 {
2221                     sal_uInt16 nNewChars =
2222                         mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen;
2223 
2224                     aPrevSel.GetStart().GetIndex() =
2225                         aPrevSel.GetStart().GetIndex() + nNewChars;
2226                     if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() )
2227                         aPrevSel.GetEnd().GetIndex() =
2228                             aPrevSel.GetEnd().GetIndex() + nNewChars;
2229                 }
2230             }
2231             else
2232             {
2233                 // aktuelle Selektion anpassen
2234                 TextPaM aPaM = mpImpl->maSelection.GetStart();
2235                 aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() );
2236                 if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() )
2237                 {
2238                     aPaM.GetIndex() =
2239                         aPaM.GetIndex() - aPrevSel.GetEnd().GetIndex();
2240                     if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() )
2241                         aPaM.GetIndex() =
2242                             aPaM.GetIndex() + aPrevSel.GetStart().GetIndex();
2243                 }
2244                 ImpSetSelection( aPaM );
2245 
2246             }
2247             mpImpl->mpTextEngine->ImpDeleteText( aPrevSel );
2248         }
2249 
2250         mpImpl->mpTextEngine->UndoActionEnd();
2251 
2252         delete mpImpl->mpDDInfo;
2253         mpImpl->mpDDInfo = 0;
2254 
2255         mpImpl->mpTextEngine->FormatAndUpdate( this );
2256 
2257         mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
2258     }
2259     rDTDE.Context->dropComplete( bChanges );
2260 }
2261 
2262 void TextView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException)
2263 {
2264 }
2265 
2266 void TextView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
2267 {
2268     vos::OGuard aVclGuard( Application::GetSolarMutex() );
2269     ImpHideDDCursor();
2270 }
2271 
2272 void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
2273 {
2274     vos::OGuard aVclGuard( Application::GetSolarMutex() );
2275 
2276     if ( !mpImpl->mpDDInfo )
2277         mpImpl->mpDDInfo = new TextDDInfo;
2278 
2279     TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos;
2280     Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
2281     Point aDocPos = GetDocPos( aMousePos );
2282     mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos );
2283 
2284 /*
2285     Size aOutSize = mpImpl->mpWindow->GetOutputSizePixel();
2286     if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) ||
2287          ( aMousePos.Y() < 0 ) || ( aMousePos.Y() > aOutSize.Height() ) )
2288     {
2289         // Scroll?
2290         // No, I will not receive events for this...
2291     }
2292 */
2293 
2294     sal_Bool bProtected = sal_False;
2295     if(mpImpl->mbSupportProtectAttribute)
2296     {
2297         const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
2298                     mpImpl->mpDDInfo->maDropPos,
2299                     TEXTATTR_PROTECTED );
2300         bProtected = pStartAttr != 0 &&
2301                 pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() &&
2302                 pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex();
2303     }
2304     // Don't drop in selection or in read only engine
2305     if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected)
2306     {
2307         ImpHideDDCursor();
2308         rDTDE.Context->rejectDrag();
2309     }
2310     else
2311     {
2312         // Alten Cursor wegzeichnen...
2313         if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) )
2314         {
2315             ImpHideDDCursor();
2316             ImpShowDDCursor();
2317         }
2318         rDTDE.Context->acceptDrag( rDTDE.DropAction );
2319     }
2320 }
2321 
2322 Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const
2323 {
2324     Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() );
2325     if ( mpImpl->mpTextEngine->IsRightToLeft() )
2326     {
2327         Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
2328         aStartPos.X() = rStartDocPos.X() + aSz.Width() - 1; // -1: Start is 0
2329     }
2330     return aStartPos;
2331 }
2332 
2333 Point TextView::GetDocPos( const Point& rWindowPos ) const
2334 {
2335     // Fensterposition => Dokumentposition
2336 
2337     Point aPoint;
2338 
2339     aPoint.Y() = rWindowPos.Y() + mpImpl->maStartDocPos.Y();
2340 
2341     if ( !mpImpl->mpTextEngine->IsRightToLeft() )
2342     {
2343         aPoint.X() = rWindowPos.X() + mpImpl->maStartDocPos.X();
2344     }
2345     else
2346     {
2347         Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
2348         aPoint.X() = ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X();
2349     }
2350 
2351     return aPoint;
2352 }
2353 
2354 Point TextView::GetWindowPos( const Point& rDocPos ) const
2355 {
2356     // Dokumentposition => Fensterposition
2357 
2358     Point aPoint;
2359 
2360     aPoint.Y() = rDocPos.Y() - mpImpl->maStartDocPos.Y();
2361 
2362     if ( !mpImpl->mpTextEngine->IsRightToLeft() )
2363     {
2364         aPoint.X() = rDocPos.X() - mpImpl->maStartDocPos.X();
2365     }
2366     else
2367     {
2368         Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
2369         aPoint.X() = ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() );
2370     }
2371 
2372     return aPoint;
2373 }
2374 
2375 sal_Int32 TextView::GetLineNumberOfCursorInSelection() const
2376 {
2377  // PROGRESS
2378     sal_Int32 nLineNo = -1;
2379     if( mpImpl->mbCursorEnabled )
2380     {
2381         TextPaM aPaM = GetSelection().GetEnd();
2382         TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
2383         nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
2384         if( mpImpl->mbCursorAtEndOfLine )
2385             --nLineNo;
2386     }
2387     return nLineNo;
2388 }
2389 
2390 
2391 // -------------------------------------------------------------------------
2392 // (+) class TextSelFunctionSet
2393 // -------------------------------------------------------------------------
2394 TextSelFunctionSet::TextSelFunctionSet( TextView* pView )
2395 {
2396     mpView = pView;
2397 }
2398 
2399 void __EXPORT TextSelFunctionSet::BeginDrag()
2400 {
2401 }
2402 
2403 void __EXPORT TextSelFunctionSet::CreateAnchor()
2404 {
2405 //  TextSelection aSel( mpView->GetSelection() );
2406 //  aSel.GetStart() = aSel.GetEnd();
2407 //  mpView->SetSelection( aSel );
2408 
2409     // Es darf kein ShowCursor folgen:
2410     mpView->HideSelection();
2411     mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() );
2412 }
2413 
2414 sal_Bool __EXPORT TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, sal_Bool )
2415 {
2416     return mpView->SetCursorAtPoint( rPointPixel );
2417 }
2418 
2419 sal_Bool __EXPORT TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
2420 {
2421     return mpView->IsSelectionAtPoint( rPointPixel );
2422 }
2423 
2424 void __EXPORT TextSelFunctionSet::DeselectAll()
2425 {
2426     CreateAnchor();
2427 }
2428 
2429 void __EXPORT TextSelFunctionSet::DeselectAtPoint( const Point& )
2430 {
2431     // Nur bei Mehrfachselektion
2432 }
2433 
2434 void __EXPORT TextSelFunctionSet::DestroyAnchor()
2435 {
2436     // Nur bei Mehrfachselektion
2437 }
2438 TextEngine*         TextView::GetTextEngine() const
2439 { return mpImpl->mpTextEngine; }
2440 Window*             TextView::GetWindow() const
2441 { return mpImpl->mpWindow; }
2442 void                TextView::EnableCursor( sal_Bool bEnable )
2443 { mpImpl->mbCursorEnabled = bEnable; }
2444 sal_Bool                TextView::IsCursorEnabled() const
2445 { return mpImpl->mbCursorEnabled; }
2446 void                TextView::SetStartDocPos( const Point& rPos )
2447 { mpImpl->maStartDocPos = rPos; }
2448 const Point&        TextView::GetStartDocPos() const
2449 { return mpImpl->maStartDocPos; }
2450 void                TextView::SetAutoIndentMode( sal_Bool bAutoIndent )
2451 { mpImpl->mbAutoIndent = bAutoIndent; }
2452 sal_Bool                TextView::IsAutoIndentMode() const
2453 { return mpImpl->mbAutoIndent; }
2454 sal_Bool                TextView::IsReadOnly() const
2455 { return mpImpl->mbReadOnly; }
2456 void                TextView::SetAutoScroll( sal_Bool bAutoScroll )
2457 { mpImpl->mbAutoScroll = bAutoScroll; }
2458 sal_Bool                TextView::IsAutoScroll() const
2459 { return mpImpl->mbAutoScroll; }
2460 sal_Bool                TextView::IsPaintSelection() const
2461 { return mpImpl->mbPaintSelection; }
2462 sal_Bool                TextView::IsHighlightSelection() const
2463 { return mpImpl->mbHighlightSelection; }
2464 sal_Bool                TextView::HasSelection() const
2465 { return mpImpl->maSelection.HasRange(); }
2466 sal_Bool                TextView::IsInsertMode() const
2467 { return mpImpl->mbInsertMode; }
2468 void                TextView::SupportProtectAttribute(sal_Bool bSupport)
2469 { mpImpl->mbSupportProtectAttribute = bSupport;}
2470 
2471