Update ooo320-m1
[ooovba.git] / svtools / source / edit / textview.cxx
blob4cd10f362ca666759dc7fb575f5112d20d1311b5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: textview.cxx,v $
10 * $Revision: 1.59 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
33 #include <svtools/textview.hxx>
34 #include <svtools/texteng.hxx>
35 #include <textdoc.hxx>
36 #include <svtools/textdata.hxx>
37 #include <textdat2.hxx>
39 #include <svtools/undo.hxx>
40 #include <vcl/cursor.hxx>
41 #include <vcl/window.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/sound.hxx>
44 #include <tools/stream.hxx>
46 #include <sot/formats.hxx>
47 #include <urlbmk.hxx>
49 #ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_
50 #include <com/sun/star/i18n/XBreakIterator.hpp>
51 #endif
53 #ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_
54 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
55 #endif
57 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
58 #include <com/sun/star/i18n/WordType.hpp>
59 #endif
60 #include <cppuhelper/weak.hxx>
61 #include <vcl/unohelp.hxx>
62 #include <com/sun/star/datatransfer/XTransferable.hpp>
63 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
64 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
65 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
67 #ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_
68 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
69 #endif
70 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
71 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
73 #include <vcl/edit.hxx>
76 #include <sot/exchange.hxx>
77 #include <sot/formats.hxx>
79 #include <vos/mutex.hxx>
82 using namespace ::com::sun::star;
84 class TETextDataObject : public ::com::sun::star::datatransfer::XTransferable,
85 public ::cppu::OWeakObject
88 private:
89 String maText;
90 SvMemoryStream maHTMLStream;
92 public:
93 TETextDataObject( const String& rText );
94 ~TETextDataObject();
96 String& GetText() { return maText; }
97 SvMemoryStream& GetHTMLStream() { return maHTMLStream; }
99 // ::com::sun::star::uno::XInterface
100 ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
101 void SAL_CALL acquire() throw() { OWeakObject::acquire(); }
102 void SAL_CALL release() throw() { OWeakObject::release(); }
104 // ::com::sun::star::datatransfer::XTransferable
105 ::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);
106 ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException);
107 sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException);
110 TETextDataObject::TETextDataObject( const String& rText ) : maText( rText )
114 TETextDataObject::~TETextDataObject()
118 // uno::XInterface
119 uno::Any TETextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException)
121 uno::Any aRet = ::cppu::queryInterface( rType, SAL_STATIC_CAST( datatransfer::XTransferable*, this ) );
122 return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
125 // datatransfer::XTransferable
126 uno::Any TETextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException)
128 uno::Any aAny;
130 ULONG nT = SotExchange::GetFormat( rFlavor );
131 if ( nT == SOT_FORMAT_STRING )
133 aAny <<= (::rtl::OUString)GetText();
135 else if ( nT == SOT_FORMATSTR_ID_HTML )
137 GetHTMLStream().Seek( STREAM_SEEK_TO_END );
138 ULONG nLen = GetHTMLStream().Tell();
139 GetHTMLStream().Seek(0);
141 uno::Sequence< sal_Int8 > aSeq( nLen );
142 memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen );
143 aAny <<= aSeq;
145 else
147 throw datatransfer::UnsupportedFlavorException();
149 return aAny;
152 uno::Sequence< datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException)
154 GetHTMLStream().Seek( STREAM_SEEK_TO_END );
155 BOOL bHTML = GetHTMLStream().Tell() > 0;
156 uno::Sequence< datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 );
157 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] );
158 if ( bHTML )
159 SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_HTML, aDataFlavors.getArray()[1] );
160 return aDataFlavors;
163 sal_Bool TETextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException)
165 ULONG nT = SotExchange::GetFormat( rFlavor );
166 return ( nT == SOT_FORMAT_STRING );
169 /*-- 24.06.2004 13:54:36---------------------------------------------------
171 -----------------------------------------------------------------------*/
172 struct ImpTextView
174 TextEngine* mpTextEngine;
176 Window* mpWindow;
177 TextSelection maSelection;
178 Point maStartDocPos;
179 // TextPaM maMBDownPaM;
181 Cursor* mpCursor;
183 TextDDInfo* mpDDInfo;
185 VirtualDevice* mpVirtDev;
187 SelectionEngine* mpSelEngine;
188 TextSelFunctionSet* mpSelFuncSet;
190 ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener;
192 USHORT mnTravelXPos;
194 BOOL mbAutoScroll : 1;
195 BOOL mbInsertMode : 1;
196 BOOL mbReadOnly : 1;
197 BOOL mbPaintSelection : 1;
198 BOOL mbAutoIndent : 1;
199 BOOL mbHighlightSelection : 1;
200 BOOL mbCursorEnabled : 1;
201 BOOL mbClickedInSelection : 1;
202 BOOL mbSupportProtectAttribute : 1;
203 bool mbCursorAtEndOfLine;
206 // -------------------------------------------------------------------------
207 // (+) class TextView
208 // -------------------------------------------------------------------------
209 TextView::TextView( TextEngine* pEng, Window* pWindow ) :
210 mpImpl(new ImpTextView)
212 pWindow->EnableRTL( FALSE );
214 mpImpl->mpWindow = pWindow;
215 mpImpl->mpTextEngine = pEng;
216 mpImpl->mpVirtDev = NULL;
218 mpImpl->mbPaintSelection = TRUE;
219 mpImpl->mbAutoScroll = TRUE;
220 mpImpl->mbInsertMode = TRUE;
221 mpImpl->mbReadOnly = FALSE;
222 mpImpl->mbHighlightSelection = FALSE;
223 mpImpl->mbAutoIndent = FALSE;
224 mpImpl->mbCursorEnabled = TRUE;
225 mpImpl->mbClickedInSelection = FALSE;
226 mpImpl->mbSupportProtectAttribute = FALSE;
227 mpImpl->mbCursorAtEndOfLine = false;
228 // mbInSelection = FALSE;
230 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
232 mpImpl->mpSelFuncSet = new TextSelFunctionSet( this );
233 mpImpl->mpSelEngine = new SelectionEngine( mpImpl->mpWindow, mpImpl->mpSelFuncSet );
234 mpImpl->mpSelEngine->SetSelectionMode( RANGE_SELECTION );
235 mpImpl->mpSelEngine->EnableDrag( TRUE );
237 mpImpl->mpCursor = new Cursor;
238 mpImpl->mpCursor->Show();
239 pWindow->SetCursor( mpImpl->mpCursor );
240 pWindow->SetInputContext( InputContext( pEng->GetFont(), INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT ) );
242 if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT )
243 mpImpl->mbHighlightSelection = TRUE;
245 pWindow->SetLineColor();
247 mpImpl->mpDDInfo = NULL;
249 if ( pWindow->GetDragGestureRecognizer().is() )
251 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
252 mpImpl->mxDnDListener = pDnDWrapper;
254 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, uno::UNO_QUERY );
255 pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL );
256 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY );
257 pWindow->GetDropTarget()->addDropTargetListener( xDTL );
258 pWindow->GetDropTarget()->setActive( sal_True );
259 pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
263 TextView::~TextView()
265 delete mpImpl->mpSelEngine;
266 delete mpImpl->mpSelFuncSet;
267 delete mpImpl->mpVirtDev;
269 if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor )
270 mpImpl->mpWindow->SetCursor( 0 );
271 delete mpImpl->mpCursor;
272 delete mpImpl->mpDDInfo;
273 delete mpImpl;
276 void TextView::Invalidate()
278 mpImpl->mpWindow->Invalidate();
281 void TextView::SetSelection( const TextSelection& rTextSel, BOOL bGotoCursor )
283 // Falls jemand gerade ein leeres Attribut hinterlassen hat,
284 // und dann der Outliner die Selektion manipulitert:
285 if ( !mpImpl->maSelection.HasRange() )
286 mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() );
288 // Wenn nach einem KeyInput die Selection manipuliert wird:
289 mpImpl->mpTextEngine->CheckIdleFormatter();
291 HideSelection();
292 TextSelection aNewSel( rTextSel );
293 mpImpl->mpTextEngine->ValidateSelection( aNewSel );
294 ImpSetSelection( aNewSel );
295 ShowSelection();
296 ShowCursor( bGotoCursor );
299 void TextView::SetSelection( const TextSelection& rTextSel )
301 SetSelection( rTextSel, mpImpl->mbAutoScroll );
304 const TextSelection& TextView::GetSelection() const
306 return mpImpl->maSelection;
308 TextSelection& TextView::GetSelection()
310 return mpImpl->maSelection;
313 void TextView::DeleteSelected()
315 // HideSelection();
317 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DELETE );
318 TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
319 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE );
321 ImpSetSelection( aPaM );
322 mpImpl->mpTextEngine->FormatAndUpdate( this );
323 ShowCursor();
326 void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection )
328 if ( !mpImpl->mbPaintSelection )
329 pSelection = NULL;
330 else
332 // Richtige Hintergrundfarbe einstellen.
333 // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat.
334 Font aFont = mpImpl->mpTextEngine->GetFont();
335 Color aColor = pOut->GetBackground().GetColor();
336 aColor.SetTransparency( 0 );
337 if ( aColor != aFont.GetFillColor() )
339 if( aFont.IsTransparent() )
340 aColor = Color( COL_TRANSPARENT );
341 aFont.SetFillColor( aColor );
342 mpImpl->mpTextEngine->maFont = aFont;
346 mpImpl->mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection );
349 void TextView::Paint( const Rectangle& rRect )
351 ImpPaint( rRect, FALSE );
354 void TextView::ImpPaint( const Rectangle& rRect, BOOL bUseVirtDev )
356 if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() )
357 return;
359 TextSelection *pDrawSelection = NULL;
360 if ( !mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange() )
361 pDrawSelection = &mpImpl->maSelection;
363 if ( bUseVirtDev )
365 VirtualDevice* pVDev = GetVirtualDevice();
367 const Color& rBackgroundColor = mpImpl->mpWindow->GetBackground().GetColor();
368 if ( pVDev->GetFillColor() != rBackgroundColor )
369 pVDev->SetFillColor( rBackgroundColor );
370 if ( pVDev->GetBackground().GetColor() != rBackgroundColor )
371 pVDev->SetBackground( rBackgroundColor );
373 BOOL bVDevValid = TRUE;
374 Size aOutSz( pVDev->GetOutputSizePixel() );
375 if ( ( aOutSz.Width() < rRect.GetWidth() ) ||
376 ( aOutSz.Height() < rRect.GetHeight() ) )
378 bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() );
380 else
382 // Das VirtDev kann bei einem Resize sehr gross werden =>
383 // irgendwann mal kleiner machen!
384 if ( ( aOutSz.Height() > ( rRect.GetHeight() + 20 ) ) ||
385 ( aOutSz.Width() > ( rRect.GetWidth() + 20 ) ) )
387 bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() );
389 else
391 pVDev->Erase();
394 if ( !bVDevValid )
396 ImpPaint( rRect, FALSE /* ohne VDev */ );
397 return;
400 Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() );
402 Point aDocPos( mpImpl->maStartDocPos.X(), mpImpl->maStartDocPos.Y() + rRect.Top() );
403 Point aStartPos = ImpGetOutputStartPos( aDocPos );
404 ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pDrawSelection );
405 mpImpl->mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(),
406 Point(0,0), rRect.GetSize(), *pVDev );
407 // ShowSelection();
408 if ( mpImpl->mbHighlightSelection )
409 ImpHighlight( mpImpl->maSelection );
411 else
413 Point aStartPos = ImpGetOutputStartPos( mpImpl->maStartDocPos );
414 ImpPaint( mpImpl->mpWindow, aStartPos, &rRect, NULL, pDrawSelection );
416 // ShowSelection();
417 if ( mpImpl->mbHighlightSelection )
418 ImpHighlight( mpImpl->maSelection );
422 void TextView::ImpHighlight( const TextSelection& rSel )
424 TextSelection aSel( rSel );
425 aSel.Justify();
426 if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() )
428 mpImpl->mpCursor->Hide();
430 DBG_ASSERT( !mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" );
432 Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() );
433 long nY = 0;
434 ULONG nStartPara = aSel.GetStart().GetPara();
435 ULONG nEndPara = aSel.GetEnd().GetPara();
436 for ( ULONG nPara = 0; nPara <= nEndPara; nPara++ )
438 long nParaHeight = (long)mpImpl->mpTextEngine->CalcParaHeight( nPara );
439 if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) )
441 TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara );
442 USHORT nStartLine = 0;
443 USHORT nEndLine = pTEParaPortion->GetLines().Count() -1;
444 if ( nPara == nStartPara )
445 nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), FALSE );
446 if ( nPara == nEndPara )
447 nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), TRUE );
449 // ueber die Zeilen iterieren....
450 for ( USHORT nLine = nStartLine; nLine <= nEndLine; nLine++ )
452 TextLine* pLine = pTEParaPortion->GetLines().GetObject( nLine );
453 USHORT nStartIndex = pLine->GetStart();
454 USHORT nEndIndex = pLine->GetEnd();
455 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) )
456 nStartIndex = aSel.GetStart().GetIndex();
457 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) )
458 nEndIndex = aSel.GetEnd().GetIndex();
460 // Kann passieren, wenn am Anfang einer umgebrochenen Zeile.
461 if ( nEndIndex < nStartIndex )
462 nEndIndex = nStartIndex;
464 Rectangle aTmpRec( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), FALSE ) );
465 aTmpRec.Top() += nY;
466 aTmpRec.Bottom() += nY;
467 Point aTopLeft( aTmpRec.TopLeft() );
469 aTmpRec = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), TRUE );
470 aTmpRec.Top() += nY;
471 aTmpRec.Bottom() += nY;
472 Point aBottomRight( aTmpRec.BottomRight() );
473 aBottomRight.X()--;
475 // Nur Painten, wenn im sichtbaren Bereich...
476 if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) )
478 Point aPnt1( GetWindowPos( aTopLeft ) );
479 Point aPnt2( GetWindowPos( aBottomRight ) );
481 Rectangle aRect( aPnt1, aPnt2 );
482 mpImpl->mpWindow->Invert( aRect );
486 nY += nParaHeight;
488 if ( nY >= aVisArea.Bottom() )
489 break;
494 void TextView::ImpSetSelection( const TextSelection& rSelection )
496 if ( rSelection != mpImpl->maSelection )
498 mpImpl->maSelection = rSelection;
499 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSELECTIONCHANGED ) );
503 void TextView::ShowSelection()
505 ImpShowHideSelection( TRUE );
508 void TextView::HideSelection()
510 ImpShowHideSelection( FALSE );
513 void TextView::ShowSelection( const TextSelection& rRange )
515 ImpShowHideSelection( TRUE, &rRange );
518 void TextView::ImpShowHideSelection( BOOL bShow, const TextSelection* pRange )
520 const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection;
522 if ( pRangeOrSelection->HasRange() )
524 if ( mpImpl->mbHighlightSelection )
526 ImpHighlight( *pRangeOrSelection );
528 else
530 if( mpImpl->mpWindow->IsPaintTransparent() )
531 mpImpl->mpWindow->Invalidate();
532 else
534 Rectangle aOutArea( Point( 0, 0 ), mpImpl->mpWindow->GetOutputSizePixel() );
535 Point aStartPos( ImpGetOutputStartPos( mpImpl->maStartDocPos ) );
536 TextSelection aRange( *pRangeOrSelection );
537 aRange.Justify();
538 BOOL bVisCursor = mpImpl->mpCursor->IsVisible();
539 mpImpl->mpCursor->Hide();
540 ImpPaint( mpImpl->mpWindow, aStartPos, &aOutArea, &aRange, bShow ? &mpImpl->maSelection : NULL );
541 if ( bVisCursor )
542 mpImpl->mpCursor->Show();
548 VirtualDevice* TextView::GetVirtualDevice()
550 if ( !mpImpl->mpVirtDev )
552 mpImpl->mpVirtDev = new VirtualDevice;
553 mpImpl->mpVirtDev->SetLineColor();
555 return mpImpl->mpVirtDev;
558 void TextView::EraseVirtualDevice()
560 delete mpImpl->mpVirtDev;
561 mpImpl->mpVirtDev = 0;
564 BOOL TextView::KeyInput( const KeyEvent& rKeyEvent )
566 BOOL bDone = TRUE;
567 BOOL bModified = FALSE;
568 BOOL bMoved = FALSE;
569 BOOL bEndKey = FALSE; // spezielle CursorPosition
570 BOOL bAllowIdle = TRUE;
572 // Um zu pruefen ob durch irgendeine Aktion mModified, das lokale
573 // bModified wird z.B. bei Cut/Paste nicht gesetzt, weil dort an anderen
574 // Stellen das updaten erfolgt.
575 BOOL bWasModified = mpImpl->mpTextEngine->IsModified();
576 mpImpl->mpTextEngine->SetModified( FALSE );
578 TextSelection aCurSel( mpImpl->maSelection );
579 TextSelection aOldSel( aCurSel );
581 USHORT nCode = rKeyEvent.GetKeyCode().GetCode();
582 KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
583 if ( eFunc != KEYFUNC_DONTKNOW )
585 switch ( eFunc )
587 case KEYFUNC_CUT:
589 if ( !mpImpl->mbReadOnly )
590 Cut();
592 break;
593 case KEYFUNC_COPY:
595 Copy();
597 break;
598 case KEYFUNC_PASTE:
600 if ( !mpImpl->mbReadOnly )
601 Paste();
603 break;
604 case KEYFUNC_UNDO:
606 if ( !mpImpl->mbReadOnly )
607 Undo();
609 break;
610 case KEYFUNC_REDO:
612 if ( !mpImpl->mbReadOnly )
613 Redo();
615 break;
617 default: // wird dann evtl. unten bearbeitet.
618 eFunc = KEYFUNC_DONTKNOW;
621 if ( eFunc == KEYFUNC_DONTKNOW )
623 switch ( nCode )
625 case KEY_UP:
626 case KEY_DOWN:
627 case KEY_LEFT:
628 case KEY_RIGHT:
629 case KEY_HOME:
630 case KEY_END:
631 case KEY_PAGEUP:
632 case KEY_PAGEDOWN:
633 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
634 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
635 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
636 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
637 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
638 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
639 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
640 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
641 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
642 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
643 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
644 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
645 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
646 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
647 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
648 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
650 if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) )
651 && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) )
653 aCurSel = ImpMoveCursor( rKeyEvent );
654 if ( aCurSel.HasRange() ) {
655 uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
656 Copy( aSelection );
658 bMoved = TRUE;
659 if ( nCode == KEY_END )
660 bEndKey = TRUE;
662 else
663 bDone = FALSE;
665 break;
666 case KEY_BACKSPACE:
667 case KEY_DELETE:
668 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
669 case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
670 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
671 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
673 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() )
675 BYTE nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT;
676 BYTE nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE;
677 if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() )
678 nMode = DELMODE_RESTOFCONTENT;
680 switch( nCode )
682 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
683 nDel = DEL_LEFT;
684 nMode = DELMODE_RESTOFWORD;
685 break;
686 case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
687 nDel = DEL_RIGHT;
688 nMode = DELMODE_RESTOFWORD;
689 break;
690 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
691 nDel = DEL_LEFT;
692 nMode = DELMODE_RESTOFCONTENT;
693 break;
694 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
695 nDel = DEL_RIGHT;
696 nMode = DELMODE_RESTOFCONTENT;
697 break;
698 default: break;
701 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DELETE );
702 if(mpImpl->mbSupportProtectAttribute)
704 //expand selection to include all protected content - if there is any
705 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
706 TextPaM(mpImpl->maSelection.GetStart().GetPara(),
707 mpImpl->maSelection.GetStart().GetIndex()),
708 TEXTATTR_PROTECTED );
709 const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
710 TextPaM(mpImpl->maSelection.GetEnd().GetPara(),
711 mpImpl->maSelection.GetEnd().GetIndex()),
712 TEXTATTR_PROTECTED );
713 if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex())
715 mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart();
717 if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex())
719 mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd();
722 aCurSel = ImpDelete( nDel, nMode );
723 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE );
724 bModified = TRUE;
725 bAllowIdle = FALSE;
727 else
728 bDone = FALSE;
730 break;
731 case KEY_TAB:
733 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() &&
734 !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() &&
735 ImplCheckTextLen( 'x' ) )
737 aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() );
738 bModified = TRUE;
740 else
741 bDone = FALSE;
743 break;
744 case KEY_RETURN:
746 // Shift-RETURN darf nicht geschluckt werden, weil dann keine
747 // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich.
748 if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() &&
749 !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( 'x' ) )
751 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
752 aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel );
753 if ( mpImpl->mbAutoIndent )
755 TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 );
756 USHORT n = 0;
757 while ( ( n < pPrev->GetText().Len() ) && (
758 ( pPrev->GetText().GetChar( n ) == ' ' ) ||
759 ( pPrev->GetText().GetChar( n ) == '\t' ) ) )
761 n++;
763 if ( n )
764 aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) );
766 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
767 bModified = TRUE;
769 else
770 bDone = FALSE;
772 break;
773 case KEY_INSERT:
775 if ( !mpImpl->mbReadOnly )
776 SetInsertMode( !IsInsertMode() );
778 break;
779 default:
781 if ( TextEngine::IsSimpleCharInput( rKeyEvent ) )
783 xub_Unicode nCharCode = rKeyEvent.GetCharCode();
784 if ( !mpImpl->mbReadOnly && ImplCheckTextLen( nCharCode ) ) // sonst trotzdem das Zeichen schlucken...
786 aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True );
787 bModified = TRUE;
790 else
791 bDone = FALSE;
796 if ( aCurSel != aOldSel ) // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that!
797 ImpSetSelection( aCurSel );
799 mpImpl->mpTextEngine->UpdateSelections();
801 if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) )
802 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
804 if ( bModified )
806 // Idle-Formatter nur, wenn AnyInput.
807 if ( bAllowIdle && Application::AnyInput( INPUT_KEYBOARD) )
808 mpImpl->mpTextEngine->IdleFormatAndUpdate( this );
809 else
810 mpImpl->mpTextEngine->FormatAndUpdate( this);
812 else if ( bMoved )
814 // Selection wird jetzt gezielt in ImpMoveCursor gemalt.
815 ImpShowCursor( mpImpl->mbAutoScroll, TRUE, bEndKey );
818 if ( mpImpl->mpTextEngine->IsModified() )
819 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
820 else if ( bWasModified )
821 mpImpl->mpTextEngine->SetModified( TRUE );
823 return bDone;
826 void TextView::MouseButtonUp( const MouseEvent& rMouseEvent )
828 mpImpl->mbClickedInSelection = FALSE;
829 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
830 mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent );
831 if ( rMouseEvent.IsMiddle() && !IsReadOnly() &&
832 ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
834 uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
835 Paste( aSelection );
836 if ( mpImpl->mpTextEngine->IsModified() )
837 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
839 else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() )
841 uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
842 Copy( aSelection );
846 void TextView::MouseButtonDown( const MouseEvent& rMouseEvent )
848 mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown
849 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
850 mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
852 mpImpl->mpTextEngine->SetActiveView( this );
854 mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent );
856 // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed'
857 // notification. The appropriate handler could change the current selection,
858 // which is the case in the MailMerge address block control. To enable select'n'drag
859 // we need to reevaluate the selection after the notification has been fired.
860 mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
862 // Sonderbehandlungen
863 if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) )
865 if ( rMouseEvent.IsMod2() )
867 HideSelection();
868 ImpSetSelection( mpImpl->maSelection.GetEnd() );
869 SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // Wird von SelectionEngine bei MOD2 nicht gesetzt
872 if ( rMouseEvent.GetClicks() == 2 )
874 // Wort selektieren
875 if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) )
877 HideSelection();
878 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() );
879 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
880 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
881 TextSelection aNewSel( mpImpl->maSelection );
882 aNewSel.GetStart().GetIndex() = (USHORT)aBoundary.startPos;
883 aNewSel.GetEnd().GetIndex() = (USHORT)aBoundary.endPos;
884 if(mpImpl->mbSupportProtectAttribute)
886 //expand selection to include all protected content - if there is any
887 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
888 TextPaM(aNewSel.GetStart().GetPara(),
889 (USHORT)aBoundary.startPos),
890 TEXTATTR_PROTECTED );
891 const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
892 TextPaM(aNewSel.GetEnd().GetPara(),
893 (USHORT)aBoundary.endPos),
894 TEXTATTR_PROTECTED );
895 if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex())
897 aNewSel.GetStart().GetIndex() = pStartAttr->GetStart();
899 if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex())
901 aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd();
904 ImpSetSelection( aNewSel );
905 ShowSelection();
906 ShowCursor( TRUE, TRUE );
909 else if ( rMouseEvent.GetClicks() == 3 )
911 // Absatz selektieren
912 if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) )
914 HideSelection();
915 TextSelection aNewSel( mpImpl->maSelection );
916 aNewSel.GetStart().GetIndex() = 0;
917 aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() )->GetText().Len();
918 ImpSetSelection( aNewSel );
919 ShowSelection();
920 ShowCursor( TRUE, TRUE );
927 void TextView::MouseMove( const MouseEvent& rMouseEvent )
929 mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
930 mpImpl->mpSelEngine->SelMouseMove( rMouseEvent );
933 void TextView::Command( const CommandEvent& rCEvt )
935 mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown
936 mpImpl->mpTextEngine->SetActiveView( this );
938 if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
940 DeleteSelected();
941 delete mpImpl->mpTextEngine->mpIMEInfos;
942 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( GetSelection().GetEnd().GetPara() );
943 mpImpl->mpTextEngine->mpIMEInfos = new TEIMEInfos( GetSelection().GetEnd(), pNode->GetText().Copy( GetSelection().GetEnd().GetIndex() ) );
944 mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
946 else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
948 DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" );
949 if( mpImpl->mpTextEngine->mpIMEInfos )
951 TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() );
952 pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 );
954 BOOL bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite;
956 delete mpImpl->mpTextEngine->mpIMEInfos;
957 mpImpl->mpTextEngine->mpIMEInfos = NULL;
959 mpImpl->mpTextEngine->FormatAndUpdate( this );
961 SetInsertMode( bInsertMode );
963 if ( mpImpl->mpTextEngine->IsModified() )
964 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
967 else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
969 DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" );
970 if( mpImpl->mpTextEngine->mpIMEInfos )
972 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
974 if ( !pData->IsOnlyCursorChanged() )
976 TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos );
977 aSelect.GetEnd().GetIndex() = aSelect.GetEnd().GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen;
978 aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect );
979 aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() );
981 if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite )
983 USHORT nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen;
984 USHORT nNewIMETextLen = pData->GetText().Len();
986 if ( ( nOldIMETextLen > nNewIMETextLen ) &&
987 ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
989 // restore old characters
990 USHORT nRestore = nOldIMETextLen - nNewIMETextLen;
991 TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos );
992 aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen;
993 mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) );
995 else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
996 ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
998 // overwrite
999 USHORT nOverwrite = nNewIMETextLen - nOldIMETextLen;
1000 if ( ( nOldIMETextLen + nOverwrite ) > mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() )
1001 nOverwrite = mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen;
1002 DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" );
1003 TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos );
1004 aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen;
1005 TextSelection aSel( aPaM );
1006 aSel.GetEnd().GetIndex() =
1007 aSel.GetEnd().GetIndex() + nOverwrite;
1008 mpImpl->mpTextEngine->ImpDeleteText( aSel );
1012 if ( pData->GetTextAttr() )
1014 mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
1015 mpImpl->mpTextEngine->mpIMEInfos->bCursor = pData->IsCursorVisible();
1017 else
1019 mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs();
1022 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() );
1023 pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 );
1024 mpImpl->mpTextEngine->FormatAndUpdate( this );
1027 TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() );
1028 SetSelection( aNewSel );
1029 SetInsertMode( !pData->IsCursorOverwrite() );
1031 if ( pData->IsCursorVisible() )
1032 ShowCursor();
1033 else
1034 HideCursor();
1037 else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
1039 if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen )
1041 TextPaM aPaM( GetSelection().GetEnd() );
1042 Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM );
1044 USHORT nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen;
1046 if ( !mpImpl->mpTextEngine->IsFormatted() )
1047 mpImpl->mpTextEngine->FormatDoc();
1049 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1050 USHORT nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True );
1051 TextLine* pLine = pParaPortion->GetLines().GetObject( nLine );
1052 if ( pLine && ( nInputEnd > pLine->GetEnd() ) )
1053 nInputEnd = pLine->GetEnd();
1054 Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) );
1056 long nWidth = aR2.Left()-aR1.Right();
1057 aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() );
1058 GetWindow()->SetCursorRect( &aR1, nWidth );
1060 else
1062 GetWindow()->SetCursorRect();
1065 else
1067 mpImpl->mpSelEngine->Command( rCEvt );
1071 void TextView::ShowCursor( BOOL bGotoCursor, BOOL bForceVisCursor )
1073 // Die Einstellung hat mehr Gewicht:
1074 if ( !mpImpl->mbAutoScroll )
1075 bGotoCursor = FALSE;
1076 ImpShowCursor( bGotoCursor, bForceVisCursor, FALSE );
1079 void TextView::HideCursor()
1081 mpImpl->mpCursor->Hide();
1084 void TextView::Scroll( long ndX, long ndY )
1086 DBG_ASSERT( mpImpl->mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" );
1088 if ( !ndX && !ndY )
1089 return;
1091 Point aNewStartPos( mpImpl->maStartDocPos );
1093 // Vertical:
1094 aNewStartPos.Y() -= ndY;
1095 if ( aNewStartPos.Y() < 0 )
1096 aNewStartPos.Y() = 0;
1098 // Horizontal:
1099 aNewStartPos.X() -= ndX;
1100 if ( aNewStartPos.X() < 0 )
1101 aNewStartPos.X() = 0;
1103 long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X();
1104 long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y();
1106 if ( nDiffX || nDiffY )
1108 BOOL bVisCursor = mpImpl->mpCursor->IsVisible();
1109 mpImpl->mpCursor->Hide();
1110 mpImpl->mpWindow->Update();
1111 mpImpl->maStartDocPos = aNewStartPos;
1113 if ( mpImpl->mpTextEngine->IsRightToLeft() )
1114 nDiffX = -nDiffX;
1115 mpImpl->mpWindow->Scroll( nDiffX, nDiffY );
1116 mpImpl->mpWindow->Update();
1117 mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) );
1118 if ( bVisCursor && !mpImpl->mbReadOnly )
1119 mpImpl->mpCursor->Show();
1122 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) );
1125 void TextView::Undo()
1127 mpImpl->mpTextEngine->SetActiveView( this );
1128 mpImpl->mpTextEngine->GetUndoManager().Undo( 1 );
1131 void TextView::Redo()
1133 mpImpl->mpTextEngine->SetActiveView( this );
1134 mpImpl->mpTextEngine->GetUndoManager().Redo( 0 );
1137 void TextView::Cut()
1139 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_CUT );
1140 Copy();
1141 DeleteSelected();
1142 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_CUT );
1145 void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1147 if ( rxClipboard.is() )
1149 TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
1151 if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML
1152 mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, TRUE );
1154 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1158 rxClipboard->setContents( pDataObj, NULL );
1160 uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
1161 if( xFlushableClipboard.is() )
1162 xFlushableClipboard->flushClipboard();
1164 catch( const ::com::sun::star::uno::Exception& )
1168 Application::AcquireSolarMutex( nRef );
1172 void TextView::Copy()
1174 uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard());
1175 Copy( aClipboard );
1178 void TextView::Paste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1180 if ( rxClipboard.is() )
1182 uno::Reference< datatransfer::XTransferable > xDataObj;
1184 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1188 xDataObj = rxClipboard->getContents();
1190 catch( const ::com::sun::star::uno::Exception& )
1194 Application::AcquireSolarMutex( nRef );
1196 if ( xDataObj.is() )
1198 datatransfer::DataFlavor aFlavor;
1199 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
1200 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
1204 uno::Any aData = xDataObj->getTransferData( aFlavor );
1205 ::rtl::OUString aText;
1206 aData >>= aText;
1207 bool bWasTruncated = false;
1208 if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 )
1209 bWasTruncated = ImplTruncateNewText( aText );
1210 InsertNewText( aText, FALSE );
1211 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
1213 if( bWasTruncated )
1214 Edit::ShowTruncationWarning( mpImpl->mpWindow );
1216 catch( const ::com::sun::star::datatransfer::UnsupportedFlavorException& )
1224 void TextView::Paste()
1226 uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard());
1227 Paste( aClipboard );
1230 String TextView::GetSelected()
1232 return GetSelected( GetSystemLineEnd() );
1235 String TextView::GetSelected( LineEnd aSeparator )
1237 return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator );
1240 void TextView::SetInsertMode( BOOL bInsert )
1242 if ( mpImpl->mbInsertMode != bInsert )
1244 mpImpl->mbInsertMode = bInsert;
1245 ShowCursor( mpImpl->mbAutoScroll, FALSE );
1249 void TextView::SetReadOnly( BOOL bReadOnly )
1251 if ( mpImpl->mbReadOnly != bReadOnly )
1253 mpImpl->mbReadOnly = bReadOnly;
1254 if ( !mpImpl->mbReadOnly )
1255 ShowCursor( mpImpl->mbAutoScroll, FALSE );
1256 else
1257 HideCursor();
1259 GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
1263 TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent )
1265 // Eigentlich nur bei Up/Down noetig, aber was solls.
1266 mpImpl->mpTextEngine->CheckIdleFormatter();
1268 TextPaM aPaM( mpImpl->maSelection.GetEnd() );
1269 TextPaM aOldEnd( aPaM );
1271 TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom;
1272 if ( mpImpl->mpTextEngine->IsRightToLeft() )
1273 eTextDirection = TextDirectionality_RightToLeft_TopToBottom;
1275 KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection );
1277 BOOL bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? TRUE : FALSE;
1278 USHORT nCode = aTranslatedKeyEvent.GetKeyCode().GetCode();
1280 bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift();
1281 switch ( nCode )
1283 case KEY_UP: aPaM = CursorUp( aPaM );
1284 break;
1285 case KEY_DOWN: aPaM = CursorDown( aPaM );
1286 break;
1287 case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM );
1288 break;
1289 case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM );
1290 break;
1291 case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM );
1292 break;
1293 case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM );
1294 break;
1295 case KEY_LEFT: aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (USHORT)i18n::CharacterIteratorMode::SKIPCHARACTER : (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
1296 break;
1297 case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (USHORT)i18n::CharacterIteratorMode::SKIPCHARACTER : (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
1298 break;
1299 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1300 bSelect = true; // fallthrough intentional
1301 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1302 aPaM = CursorWordRight( aPaM );
1303 break;
1304 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1305 bSelect = true; // fallthrough intentional
1306 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1307 aPaM = CursorWordLeft( aPaM );
1308 break;
1309 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1310 bSelect = true; // fallthrough intentional
1311 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1312 aPaM = CursorStartOfLine( aPaM );
1313 break;
1314 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1315 bSelect = true; // fallthrough intentional
1316 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1317 aPaM = CursorEndOfLine( aPaM );
1318 break;
1319 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1320 bSelect = true; // falltthrough intentional
1321 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1322 aPaM = CursorStartOfParagraph( aPaM );
1323 break;
1324 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1325 bSelect = true; // falltthrough intentional
1326 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1327 aPaM = CursorEndOfParagraph( aPaM );
1328 break;
1329 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1330 bSelect = true; // falltthrough intentional
1331 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1332 aPaM = CursorStartOfDoc();
1333 break;
1334 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1335 bSelect = true; // falltthrough intentional
1336 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1337 aPaM = CursorEndOfDoc();
1338 break;
1341 // Bewirkt evtl. ein CreateAnchor oder Deselection all
1342 mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
1344 if ( aOldEnd != aPaM )
1346 mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() );
1349 TextSelection aOldSelection( mpImpl->maSelection );
1350 TextSelection aNewSelection( mpImpl->maSelection );
1351 aNewSelection.GetEnd() = aPaM;
1352 if ( bSelect )
1354 // Dann wird die Selektion erweitert...
1355 ImpSetSelection( aNewSelection );
1356 ShowSelection( TextSelection( aOldEnd, aPaM ) );
1358 else
1360 aNewSelection.GetStart() = aPaM;
1361 ImpSetSelection( aNewSelection );
1365 return mpImpl->maSelection;
1368 void TextView::InsertText( const XubString& rStr, BOOL bSelect )
1370 InsertNewText( rStr, bSelect );
1373 void TextView::InsertNewText( const rtl::OUString& rStr, BOOL bSelect )
1375 // HideSelection();
1376 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
1378 /* #i87633#
1379 break inserted text into chunks that fit into the underlying String
1380 based API (which has a maximum length of 65534 elements
1382 note: this will of course still cause problems for lines longer than those
1383 65534 elements, but those cases will hopefully be few.
1384 In the long run someone should switch the TextEngine to OUString instead of String
1386 sal_Int32 nLen = rStr.getLength();
1387 sal_Int32 nPos = 0;
1388 while( nLen )
1390 sal_Int32 nChunkLen = nLen > 65534 ? 65534 : nLen;
1391 String aChunk( rStr.copy( nPos, nChunkLen ) );
1393 TextSelection aNewSel( mpImpl->maSelection );
1395 TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, aChunk );
1397 if ( bSelect )
1399 aNewSel.Justify();
1400 aNewSel.GetEnd() = aPaM;
1402 else
1404 aNewSel = aPaM;
1407 ImpSetSelection( aNewSel );
1408 nLen -= nChunkLen;
1409 nPos += nChunkLen;
1411 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
1413 mpImpl->mpTextEngine->FormatAndUpdate( this );
1417 void TextView::InsertText( const XubString& rStr, BOOL bSelect )
1419 // HideSelection();
1421 TextSelection aNewSel( mpImpl->maSelection );
1423 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
1424 TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, rStr );
1425 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
1427 if ( bSelect )
1429 aNewSel.Justify();
1430 aNewSel.GetEnd() = aPaM;
1432 else
1434 aNewSel = aPaM;
1437 ImpSetSelection( aNewSel );
1439 mpImpl->mpTextEngine->FormatAndUpdate( this );
1443 // OLD
1444 TextPaM TextView::CursorLeft( const TextPaM& rPaM, BOOL bWordMode )
1446 return bWordMode ? CursorWordLeft( rPaM ) : CursorLeft( rPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
1448 // Remove (USHORT) typecasts in this file when removing this method!
1451 // OLD
1452 TextPaM TextView::CursorRight( const TextPaM& rPaM, BOOL bWordMode )
1454 return bWordMode ? CursorWordRight( rPaM ) : CursorRight( rPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
1456 // Remove (USHORT) typecasts in this file when removing this method!
1459 TextPaM TextView::CursorLeft( const TextPaM& rPaM, USHORT nCharacterIteratorMode )
1461 TextPaM aPaM( rPaM );
1463 if ( aPaM.GetIndex() )
1465 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1466 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1467 sal_Int32 nCount = 1;
1468 aPaM.GetIndex() = (USHORT)xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount );
1470 else if ( aPaM.GetPara() )
1472 aPaM.GetPara()--;
1473 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1474 aPaM.GetIndex() = pNode->GetText().Len();
1476 return aPaM;
1479 TextPaM TextView::CursorRight( const TextPaM& rPaM, USHORT nCharacterIteratorMode )
1481 TextPaM aPaM( rPaM );
1483 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1484 if ( aPaM.GetIndex() < pNode->GetText().Len() )
1486 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1487 sal_Int32 nCount = 1;
1488 aPaM.GetIndex() = (USHORT)xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount );
1490 else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
1492 aPaM.GetPara()++;
1493 aPaM.GetIndex() = 0;
1496 return aPaM;
1500 TextPaM TextView::CursorWordLeft( const TextPaM& rPaM )
1502 TextPaM aPaM( rPaM );
1504 if ( aPaM.GetIndex() )
1506 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1507 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1508 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1509 if ( aBoundary.startPos >= rPaM.GetIndex() )
1510 aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1511 aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? (USHORT)aBoundary.startPos : 0;
1513 else if ( aPaM.GetPara() )
1515 aPaM.GetPara()--;
1516 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1517 aPaM.GetIndex() = pNode->GetText().Len();
1519 return aPaM;
1523 TextPaM TextView::CursorWordRight( const TextPaM& rPaM )
1525 TextPaM aPaM( rPaM );
1527 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1528 if ( aPaM.GetIndex() < pNode->GetText().Len() )
1530 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1531 i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1532 aPaM.GetIndex() = (USHORT)aBoundary.startPos;
1534 else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
1536 aPaM.GetPara()++;
1537 aPaM.GetIndex() = 0;
1540 return aPaM;
1543 TextPaM TextView::ImpDelete( BYTE nMode, BYTE nDelMode )
1545 if ( mpImpl->maSelection.HasRange() ) // dann nur Sel. loeschen
1546 return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
1548 TextPaM aStartPaM = mpImpl->maSelection.GetStart();
1549 TextPaM aEndPaM = aStartPaM;
1550 if ( nMode == DEL_LEFT )
1552 if ( nDelMode == DELMODE_SIMPLE )
1554 aEndPaM = CursorLeft( aEndPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCHARACTER );
1556 else if ( nDelMode == DELMODE_RESTOFWORD )
1558 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
1559 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1560 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1561 if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() )
1562 aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1563 // #i63506# startPos is -1 when the paragraph starts with a tab
1564 aEndPaM.GetIndex() = (aBoundary.startPos >= 0) ? (USHORT)aBoundary.startPos : 0;
1566 else // DELMODE_RESTOFCONTENT
1568 if ( aEndPaM.GetIndex() != 0 )
1569 aEndPaM.GetIndex() = 0;
1570 else if ( aEndPaM.GetPara() )
1572 // Absatz davor
1573 aEndPaM.GetPara()--;
1574 aEndPaM.GetIndex() = 0;
1578 else
1580 if ( nDelMode == DELMODE_SIMPLE )
1582 aEndPaM = CursorRight( aEndPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
1584 else if ( nDelMode == DELMODE_RESTOFWORD )
1586 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
1587 uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
1588 i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1589 aEndPaM.GetIndex() = (USHORT)aBoundary.startPos;
1591 else // DELMODE_RESTOFCONTENT
1593 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
1594 if ( aEndPaM.GetIndex() < pNode->GetText().Len() )
1595 aEndPaM.GetIndex() = pNode->GetText().Len();
1596 else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) )
1598 // Absatz danach
1599 aEndPaM.GetPara()++;
1600 TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
1601 aEndPaM.GetIndex() = pNextNode->GetText().Len();
1606 return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) );
1611 TextPaM TextView::CursorUp( const TextPaM& rPaM )
1613 TextPaM aPaM( rPaM );
1615 long nX;
1616 if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW )
1618 nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, FALSE ).Left();
1619 mpImpl->mnTravelXPos = (USHORT)nX+1;
1621 else
1622 nX = mpImpl->mnTravelXPos;
1624 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1625 USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), FALSE );
1626 if ( nLine ) // gleicher Absatz
1628 USHORT nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX );
1629 aPaM.GetIndex() = nCharPos;
1630 // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das
1631 // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang
1632 // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor
1633 TextLine* pLine = pPPortion->GetLines().GetObject( nLine - 1 );
1634 if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) )
1635 aPaM.GetIndex()--;
1637 else if ( rPaM.GetPara() ) // vorheriger Absatz
1639 aPaM.GetPara()--;
1640 pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1641 USHORT nL = pPPortion->GetLines().Count() - 1;
1642 USHORT nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 );
1643 aPaM.GetIndex() = nCharPos;
1646 return aPaM;
1649 TextPaM TextView::CursorDown( const TextPaM& rPaM )
1651 TextPaM aPaM( rPaM );
1653 long nX;
1654 if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW )
1656 nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, FALSE ).Left();
1657 mpImpl->mnTravelXPos = (USHORT)nX+1;
1659 else
1660 nX = mpImpl->mnTravelXPos;
1662 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1663 USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), FALSE );
1664 if ( nLine < ( pPPortion->GetLines().Count() - 1 ) )
1666 USHORT nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX );
1667 aPaM.GetIndex() = nCharPos;
1669 // Sonderbehandlung siehe CursorUp...
1670 TextLine* pLine = pPPortion->GetLines().GetObject( nLine + 1 );
1671 if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() )
1672 aPaM.GetIndex()--;
1674 else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz
1676 aPaM.GetPara()++;
1677 pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1678 USHORT nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 );
1679 aPaM.GetIndex() = nCharPos;
1680 TextLine* pLine = pPPortion->GetLines().GetObject( 0 );
1681 if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().Count() > 1 ) )
1682 aPaM.GetIndex()--;
1685 return aPaM;
1688 TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM )
1690 TextPaM aPaM( rPaM );
1692 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1693 USHORT nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), FALSE );
1694 TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
1695 aPaM.GetIndex() = pLine->GetStart();
1697 return aPaM;
1700 TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM )
1702 TextPaM aPaM( rPaM );
1704 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
1705 USHORT nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), FALSE );
1706 TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
1707 aPaM.GetIndex() = pLine->GetEnd();
1709 if ( pLine->GetEnd() > pLine->GetStart() ) // Leerzeile
1711 xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((USHORT)(aPaM.GetIndex()-1) );
1712 if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().Len() ) )
1714 // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn,
1715 // davor zu stehen, da der Anwender hinter das Wort will.
1716 // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End!
1717 aPaM.GetIndex()--;
1720 return aPaM;
1723 TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM )
1725 TextPaM aPaM( rPaM );
1726 aPaM.GetIndex() = 0;
1727 return aPaM;
1730 TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM )
1732 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( rPaM.GetPara() );
1733 TextPaM aPaM( rPaM );
1734 aPaM.GetIndex() = pNode->GetText().Len();
1735 return aPaM;
1738 TextPaM TextView::CursorStartOfDoc()
1740 TextPaM aPaM( 0, 0 );
1741 return aPaM;
1744 TextPaM TextView::CursorEndOfDoc()
1746 ULONG nNode = mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1;
1747 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( nNode );
1748 TextPaM aPaM( nNode, pNode->GetText().Len() );
1749 return aPaM;
1752 TextPaM TextView::PageUp( const TextPaM& rPaM )
1754 Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM );
1755 Point aTopLeft = aRec.TopLeft();
1756 aTopLeft.Y() -= mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10;
1757 aTopLeft.X() += 1;
1758 if ( aTopLeft.Y() < 0 )
1759 aTopLeft.Y() = 0;
1761 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft );
1762 return aPaM;
1765 TextPaM TextView::PageDown( const TextPaM& rPaM )
1767 Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM );
1768 Point aBottomRight = aRec.BottomRight();
1769 aBottomRight.Y() += mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10;
1770 aBottomRight.X() += 1;
1771 long nHeight = mpImpl->mpTextEngine->GetTextHeight();
1772 if ( aBottomRight.Y() > nHeight )
1773 aBottomRight.Y() = nHeight-1;
1775 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight );
1776 return aPaM;
1779 void TextView::ImpShowCursor( BOOL bGotoCursor, BOOL bForceVisCursor, BOOL bSpecial )
1781 if ( mpImpl->mpTextEngine->IsFormatting() )
1782 return;
1783 if ( mpImpl->mpTextEngine->GetUpdateMode() == FALSE )
1784 return;
1785 if ( mpImpl->mpTextEngine->IsInUndo() )
1786 return;
1788 mpImpl->mpTextEngine->CheckIdleFormatter();
1789 if ( !mpImpl->mpTextEngine->IsFormatted() )
1790 mpImpl->mpTextEngine->FormatAndUpdate( this );
1793 TextPaM aPaM( mpImpl->maSelection.GetEnd() );
1794 Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial );
1796 // Remember that we placed the cursor behind the last character of a line
1797 mpImpl->mbCursorAtEndOfLine = false;
1798 if( bSpecial )
1800 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1801 mpImpl->mbCursorAtEndOfLine =
1802 pParaPortion->GetLineNumber( aPaM.GetIndex(), TRUE ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), FALSE );
1805 if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() )
1807 TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
1808 if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) )
1810 // If we are behind a portion, and the next portion has other direction, we must change position...
1811 aEditCursor.Left() = aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aPaM, FALSE, TRUE ).Left();
1813 TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
1815 USHORT nTextPortionStart = 0;
1816 USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, TRUE );
1817 TETextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion );
1818 if ( pTextPortion->GetKind() == PORTIONKIND_TAB )
1820 if ( mpImpl->mpTextEngine->IsRightToLeft() )
1824 aEditCursor.Right() += pTextPortion->GetWidth();
1826 else
1828 TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
1829 aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, TRUE ).Left();
1834 Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel();
1835 if ( aEditCursor.GetHeight() > aOutSz.Height() )
1836 aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1;
1838 aEditCursor.Left() -= 1;
1840 if ( bGotoCursor
1841 // #i81283# protext maStartDocPos against initialization problems
1842 && aOutSz.Width() && aOutSz.Height()
1845 long nVisStartY = mpImpl->maStartDocPos.Y();
1846 long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height();
1847 long nVisStartX = mpImpl->maStartDocPos.X();
1848 long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width();
1849 long nMoreX = aOutSz.Width() / 4;
1851 Point aNewStartPos( mpImpl->maStartDocPos );
1853 if ( aEditCursor.Bottom() > nVisEndY )
1855 aNewStartPos.Y() += ( aEditCursor.Bottom() - nVisEndY );
1857 else if ( aEditCursor.Top() < nVisStartY )
1859 aNewStartPos.Y() -= ( nVisStartY - aEditCursor.Top() );
1862 if ( aEditCursor.Right() >= nVisEndX )
1864 aNewStartPos.X() += ( aEditCursor.Right() - nVisEndX );
1866 // Darfs ein bischen mehr sein?
1867 aNewStartPos.X() += nMoreX;
1869 else if ( aEditCursor.Left() <= nVisStartX )
1871 aNewStartPos.X() -= ( nVisStartX - aEditCursor.Left() );
1873 // Darfs ein bischen mehr sein?
1874 aNewStartPos.X() -= nMoreX;
1877 // X kann durch das 'bischen mehr' falsch sein:
1878 // ULONG nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth();
1879 // if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) )
1880 // nMaxTextWidth = 0x7FFFFFFF;
1881 // long nMaxX = (long)nMaxTextWidth - aOutSz.Width();
1882 long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width();
1883 if ( nMaxX < 0 )
1884 nMaxX = 0;
1886 if ( aNewStartPos.X() < 0 )
1887 aNewStartPos.X() = 0;
1888 else if ( aNewStartPos.X() > nMaxX )
1889 aNewStartPos.X() = nMaxX;
1891 // Y sollte nicht weiter unten als noetig liegen:
1892 long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height();
1893 if ( nYMax < 0 )
1894 nYMax = 0;
1895 if ( aNewStartPos.Y() > nYMax )
1896 aNewStartPos.Y() = nYMax;
1898 if ( aNewStartPos != mpImpl->maStartDocPos )
1899 Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) );
1902 if ( aEditCursor.Right() < aEditCursor.Left() )
1904 long n = aEditCursor.Left();
1905 aEditCursor.Left() = aEditCursor.Right();
1906 aEditCursor.Right() = n;
1909 Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) );
1910 mpImpl->mpCursor->SetPos( aPoint );
1911 mpImpl->mpCursor->SetSize( aEditCursor.GetSize() );
1912 if ( bForceVisCursor && mpImpl->mbCursorEnabled )
1913 mpImpl->mpCursor->Show();
1916 BOOL TextView::SetCursorAtPoint( const Point& rPosPixel )
1918 mpImpl->mpTextEngine->CheckIdleFormatter();
1920 Point aDocPos = GetDocPos( rPosPixel );
1922 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos );
1924 // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion
1925 TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM );
1926 TextSelection aNewSel( mpImpl->maSelection );
1927 aNewSel.GetEnd() = aPaM;
1929 if ( !mpImpl->mpSelEngine->HasAnchor() )
1931 if ( mpImpl->maSelection.GetStart() != aPaM )
1932 mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() );
1933 aNewSel.GetStart() = aPaM;
1934 ImpSetSelection( aNewSel );
1936 else
1938 ImpSetSelection( aNewSel );
1939 ShowSelection( aTmpNewSel );
1942 BOOL bForceCursor = mpImpl->mpDDInfo ? FALSE : TRUE; // && !mbInSelection
1943 ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, FALSE );
1944 return TRUE;
1947 BOOL TextView::IsSelectionAtPoint( const Point& rPosPixel )
1949 // if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection )
1950 // return FALSE;
1952 Point aDocPos = GetDocPos( rPosPixel );
1953 TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos, FALSE );
1954 // Bei Hyperlinks D&D auch ohne Selektion starten.
1955 // BeginDrag wird aber nur gerufen, wenn IsSelectionAtPoint()
1956 // Problem: IsSelectionAtPoint wird bei Command() nicht gerufen,
1957 // wenn vorher im MBDown schon FALSE returnt wurde.
1958 return ( IsInSelection( aPaM ) ||
1959 ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) );
1962 BOOL TextView::IsInSelection( const TextPaM& rPaM )
1964 TextSelection aSel = mpImpl->maSelection;
1965 aSel.Justify();
1967 ULONG nStartNode = aSel.GetStart().GetPara();
1968 ULONG nEndNode = aSel.GetEnd().GetPara();
1969 ULONG nCurNode = rPaM.GetPara();
1971 if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) )
1972 return TRUE;
1974 if ( nStartNode == nEndNode )
1976 if ( nCurNode == nStartNode )
1977 if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
1978 return TRUE;
1980 else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) )
1981 return TRUE;
1982 else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
1983 return TRUE;
1985 return FALSE;
1988 void TextView::ImpHideDDCursor()
1990 if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor )
1992 mpImpl->mpDDInfo->maCursor.Hide();
1993 mpImpl->mpDDInfo->mbVisCursor = FALSE;
1997 void TextView::ImpShowDDCursor()
1999 if ( !mpImpl->mpDDInfo->mbVisCursor )
2001 Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, TRUE );
2002 aCursor.Right()++;
2003 aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) );
2005 mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow );
2006 mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() );
2007 mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() );
2008 mpImpl->mpDDInfo->maCursor.Show();
2009 mpImpl->mpDDInfo->mbVisCursor = TRUE;
2013 void TextView::SetPaintSelection( BOOL bPaint )
2015 if ( bPaint != mpImpl->mbPaintSelection )
2017 mpImpl->mbPaintSelection = bPaint;
2018 ShowSelection( mpImpl->maSelection );
2022 void TextView::SetHighlightSelection( BOOL bSelectByHighlight )
2024 if ( bSelectByHighlight != mpImpl->mbHighlightSelection )
2026 // Falls umschalten zwischendurch moeglich...
2027 mpImpl->mbHighlightSelection = bSelectByHighlight;
2031 BOOL TextView::Read( SvStream& rInput )
2033 BOOL bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection );
2034 ShowCursor();
2035 return bDone;
2038 BOOL TextView::Write( SvStream& rOutput )
2040 return mpImpl->mpTextEngine->Read( rOutput, &mpImpl->maSelection );
2043 bool TextView::ImplTruncateNewText( rtl::OUString& rNewText ) const
2045 bool bTruncated = false;
2047 if( rNewText.getLength() > 65534 ) // limit to String API
2049 rNewText = rNewText.copy( 0, 65534 );
2050 bTruncated = true;
2053 ULONG nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen();
2054 // 0 means unlimited, there is just the String API limit handled above
2055 if( nMaxLen != 0 )
2057 ULONG nCurLen = mpImpl->mpTextEngine->GetTextLen();
2059 sal_uInt32 nNewLen = rNewText.getLength();
2060 if ( nCurLen + nNewLen > nMaxLen )
2062 // see how much text will be replaced
2063 ULONG nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection );
2064 if ( nCurLen + nNewLen - nSelLen > nMaxLen )
2066 sal_uInt32 nTruncatedLen = static_cast<sal_uInt32>(nMaxLen - (nCurLen - nSelLen));
2067 rNewText = rNewText.copy( 0, nTruncatedLen );
2068 bTruncated = true;
2072 return bTruncated;
2075 BOOL TextView::ImplCheckTextLen( const String& rNewText )
2077 BOOL bOK = TRUE;
2078 if ( mpImpl->mpTextEngine->GetMaxTextLen() )
2080 ULONG n = mpImpl->mpTextEngine->GetTextLen();
2081 n += rNewText.Len();
2082 if ( n > mpImpl->mpTextEngine->GetMaxTextLen() )
2084 // nur dann noch ermitteln, wie viel Text geloescht wird
2085 n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection );
2086 if ( n > mpImpl->mpTextEngine->GetMaxTextLen() )
2088 // Beep hat hier eigentlich nichts verloren, sondern lieber ein Hdl,
2089 // aber so funktioniert es wenigstens in ME, BasicIDE, SourceView
2090 Sound::Beep();
2091 bOK = FALSE;
2095 return bOK;
2098 void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
2100 if ( mpImpl->mbClickedInSelection )
2102 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2104 DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" );
2106 delete mpImpl->mpDDInfo;
2107 mpImpl->mpDDInfo = new TextDDInfo;
2108 mpImpl->mpDDInfo->mbStarterOfDD = TRUE;
2110 TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
2112 if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML
2113 mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, TRUE );
2117 // D&D eines Hyperlinks.
2118 // Besser waere es im MBDown sich den MBDownPaM zu merken,
2119 // ist dann aber inkompatibel => spaeter mal umstellen.
2120 TextPaM aPaM( mpImpl->mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) );
2121 const TextCharAttrib* pAttr = mpImpl->mpTextEngine->FindCharAttrib( aPaM, TEXTATTR_HYPERLINK );
2122 if ( pAttr )
2124 aSel = aPaM;
2125 aSel.GetStart().GetIndex() = pAttr->GetStart();
2126 aSel.GetEnd().GetIndex() = pAttr->GetEnd();
2128 const TextAttribHyperLink& rLink = (const TextAttribHyperLink&)pAttr->GetAttr();
2129 String aText( rLink.GetDescription() );
2130 if ( !aText.Len() )
2131 aText = mpImpl->mpTextEngine->GetText( aSel );
2132 INetBookmark aBookmark( rLink.GetURL(), aText );
2133 aBookmark.CopyDragServer();
2137 mpImpl->mpCursor->Hide();
2139 sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
2140 if ( !IsReadOnly() )
2141 nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
2142 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener );
2146 void TextView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& ) throw (::com::sun::star::uno::RuntimeException)
2148 ImpHideDDCursor();
2149 delete mpImpl->mpDDInfo;
2150 mpImpl->mpDDInfo = NULL;
2153 void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
2155 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2157 BOOL bChanges = FALSE;
2158 if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo )
2160 ImpHideDDCursor();
2162 // Daten fuer das loeschen nach einem DROP_MOVE:
2163 TextSelection aPrevSel( mpImpl->maSelection );
2164 aPrevSel.Justify();
2165 ULONG nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount();
2166 USHORT nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() );
2168 BOOL bStarterOfDD = FALSE;
2169 for ( USHORT nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; )
2170 bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : FALSE;
2172 HideSelection();
2173 ImpSetSelection( mpImpl->mpDDInfo->maDropPos );
2175 mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DRAGANDDROP );
2177 String aText;
2178 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
2179 if ( xDataObj.is() )
2181 datatransfer::DataFlavor aFlavor;
2182 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
2183 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
2185 uno::Any aData = xDataObj->getTransferData( aFlavor );
2186 ::rtl::OUString aOUString;
2187 aData >>= aOUString;
2188 aText = aOUString;
2189 aText.ConvertLineEnd( LINEEND_LF );
2193 if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) )
2194 aText.Erase( aText.Len()-1 );
2196 TextPaM aTempStart = mpImpl->maSelection.GetStart();
2197 if ( ImplCheckTextLen( aText ) )
2198 ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) );
2199 if(mpImpl->mbSupportProtectAttribute)
2201 mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(),
2202 aTempStart.GetPara(),
2203 aTempStart.GetIndex(),
2204 mpImpl->maSelection.GetEnd().GetIndex(), FALSE );
2207 if ( aPrevSel.HasRange() &&
2208 !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element
2209 (( rDTDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) )
2211 // ggf. Selection anpasssen:
2212 if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) ||
2213 ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
2214 && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) )
2216 ULONG nNewParasBeforeSelection =
2217 mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount;
2219 aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection;
2220 aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection;
2222 if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
2224 USHORT nNewChars =
2225 mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen;
2227 aPrevSel.GetStart().GetIndex() =
2228 aPrevSel.GetStart().GetIndex() + nNewChars;
2229 if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() )
2230 aPrevSel.GetEnd().GetIndex() =
2231 aPrevSel.GetEnd().GetIndex() + nNewChars;
2234 else
2236 // aktuelle Selektion anpassen
2237 TextPaM aPaM = mpImpl->maSelection.GetStart();
2238 aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() );
2239 if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() )
2241 aPaM.GetIndex() =
2242 aPaM.GetIndex() - aPrevSel.GetEnd().GetIndex();
2243 if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() )
2244 aPaM.GetIndex() =
2245 aPaM.GetIndex() + aPrevSel.GetStart().GetIndex();
2247 ImpSetSelection( aPaM );
2250 mpImpl->mpTextEngine->ImpDeleteText( aPrevSel );
2253 mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DRAGANDDROP );
2255 delete mpImpl->mpDDInfo;
2256 mpImpl->mpDDInfo = 0;
2258 mpImpl->mpTextEngine->FormatAndUpdate( this );
2260 mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
2262 rDTDE.Context->dropComplete( bChanges );
2265 void TextView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException)
2269 void TextView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
2271 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2272 ImpHideDDCursor();
2275 void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
2277 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2279 if ( !mpImpl->mpDDInfo )
2280 mpImpl->mpDDInfo = new TextDDInfo;
2282 TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos;
2283 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
2284 Point aDocPos = GetDocPos( aMousePos );
2285 mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos );
2288 Size aOutSize = mpImpl->mpWindow->GetOutputSizePixel();
2289 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) ||
2290 ( aMousePos.Y() < 0 ) || ( aMousePos.Y() > aOutSize.Height() ) )
2292 // Scroll?
2293 // No, I will not receive events for this...
2297 sal_Bool bProtected = sal_False;
2298 if(mpImpl->mbSupportProtectAttribute)
2300 const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
2301 mpImpl->mpDDInfo->maDropPos,
2302 TEXTATTR_PROTECTED );
2303 bProtected = pStartAttr != 0 &&
2304 pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() &&
2305 pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex();
2307 // Don't drop in selection or in read only engine
2308 if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected)
2310 ImpHideDDCursor();
2311 rDTDE.Context->rejectDrag();
2313 else
2315 // Alten Cursor wegzeichnen...
2316 if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) )
2318 ImpHideDDCursor();
2319 ImpShowDDCursor();
2321 rDTDE.Context->acceptDrag( rDTDE.DropAction );
2325 Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const
2327 Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() );
2328 if ( mpImpl->mpTextEngine->IsRightToLeft() )
2330 Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
2331 aStartPos.X() = rStartDocPos.X() + aSz.Width() - 1; // -1: Start is 0
2333 return aStartPos;
2336 Point TextView::GetDocPos( const Point& rWindowPos ) const
2338 // Fensterposition => Dokumentposition
2340 Point aPoint;
2342 aPoint.Y() = rWindowPos.Y() + mpImpl->maStartDocPos.Y();
2344 if ( !mpImpl->mpTextEngine->IsRightToLeft() )
2346 aPoint.X() = rWindowPos.X() + mpImpl->maStartDocPos.X();
2348 else
2350 Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
2351 aPoint.X() = ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X();
2354 return aPoint;
2357 Point TextView::GetWindowPos( const Point& rDocPos ) const
2359 // Dokumentposition => Fensterposition
2361 Point aPoint;
2363 aPoint.Y() = rDocPos.Y() - mpImpl->maStartDocPos.Y();
2365 if ( !mpImpl->mpTextEngine->IsRightToLeft() )
2367 aPoint.X() = rDocPos.X() - mpImpl->maStartDocPos.X();
2369 else
2371 Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
2372 aPoint.X() = ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() );
2375 return aPoint;
2378 sal_Int32 TextView::GetLineNumberOfCursorInSelection() const
2380 // PROGRESS
2381 sal_Int32 nLineNo = -1;
2382 if( mpImpl->mbCursorEnabled )
2384 TextPaM aPaM = GetSelection().GetEnd();
2385 TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
2386 nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), FALSE );
2387 if( mpImpl->mbCursorAtEndOfLine )
2388 --nLineNo;
2390 return nLineNo;
2394 // -------------------------------------------------------------------------
2395 // (+) class TextSelFunctionSet
2396 // -------------------------------------------------------------------------
2397 TextSelFunctionSet::TextSelFunctionSet( TextView* pView )
2399 mpView = pView;
2402 void __EXPORT TextSelFunctionSet::BeginDrag()
2406 void __EXPORT TextSelFunctionSet::CreateAnchor()
2408 // TextSelection aSel( mpView->GetSelection() );
2409 // aSel.GetStart() = aSel.GetEnd();
2410 // mpView->SetSelection( aSel );
2412 // Es darf kein ShowCursor folgen:
2413 mpView->HideSelection();
2414 mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() );
2417 BOOL __EXPORT TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, BOOL )
2419 return mpView->SetCursorAtPoint( rPointPixel );
2422 BOOL __EXPORT TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
2424 return mpView->IsSelectionAtPoint( rPointPixel );
2427 void __EXPORT TextSelFunctionSet::DeselectAll()
2429 CreateAnchor();
2432 void __EXPORT TextSelFunctionSet::DeselectAtPoint( const Point& )
2434 // Nur bei Mehrfachselektion
2437 void __EXPORT TextSelFunctionSet::DestroyAnchor()
2439 // Nur bei Mehrfachselektion
2441 TextEngine* TextView::GetTextEngine() const
2442 { return mpImpl->mpTextEngine; }
2443 Window* TextView::GetWindow() const
2444 { return mpImpl->mpWindow; }
2445 void TextView::EnableCursor( BOOL bEnable )
2446 { mpImpl->mbCursorEnabled = bEnable; }
2447 BOOL TextView::IsCursorEnabled() const
2448 { return mpImpl->mbCursorEnabled; }
2449 void TextView::SetStartDocPos( const Point& rPos )
2450 { mpImpl->maStartDocPos = rPos; }
2451 const Point& TextView::GetStartDocPos() const
2452 { return mpImpl->maStartDocPos; }
2453 void TextView::SetAutoIndentMode( BOOL bAutoIndent )
2454 { mpImpl->mbAutoIndent = bAutoIndent; }
2455 BOOL TextView::IsAutoIndentMode() const
2456 { return mpImpl->mbAutoIndent; }
2457 BOOL TextView::IsReadOnly() const
2458 { return mpImpl->mbReadOnly; }
2459 void TextView::SetAutoScroll( BOOL bAutoScroll )
2460 { mpImpl->mbAutoScroll = bAutoScroll; }
2461 BOOL TextView::IsAutoScroll() const
2462 { return mpImpl->mbAutoScroll; }
2463 BOOL TextView::IsPaintSelection() const
2464 { return mpImpl->mbPaintSelection; }
2465 BOOL TextView::IsHighlightSelection() const
2466 { return mpImpl->mbHighlightSelection; }
2467 BOOL TextView::HasSelection() const
2468 { return mpImpl->maSelection.HasRange(); }
2469 BOOL TextView::IsInsertMode() const
2470 { return mpImpl->mbInsertMode; }
2471 void TextView::SupportProtectAttribute(sal_Bool bSupport)
2472 { mpImpl->mbSupportProtectAttribute = bSupport;}