summaryrefslogtreecommitdiff
path: root/vcl/source/edit/textview.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/edit/textview.cxx')
-rw-r--r--vcl/source/edit/textview.cxx2378
1 files changed, 2378 insertions, 0 deletions
diff --git a/vcl/source/edit/textview.cxx b/vcl/source/edit/textview.cxx
new file mode 100644
index 000000000000..045fb304b065
--- /dev/null
+++ b/vcl/source/edit/textview.cxx
@@ -0,0 +1,2378 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <vcl/textview.hxx>
+#include <vcl/texteng.hxx>
+#include <textdoc.hxx>
+#include <vcl/textdata.hxx>
+#include <textdat2.hxx>
+
+#include <svl/undo.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/stream.hxx>
+
+#include <sot/formats.hxx>
+#include <svl/urlbmk.hxx>
+
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+
+#include <com/sun/star/i18n/WordType.hpp>
+#include <cppuhelper/weak.hxx>
+#include <vcl/unohelp.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+
+#include <vcl/edit.hxx>
+
+
+#include <sot/exchange.hxx>
+
+#include <osl/mutex.hxx>
+
+
+using namespace ::com::sun::star;
+
+class TETextDataObject : public ::com::sun::star::datatransfer::XTransferable,
+ public ::cppu::OWeakObject
+
+{
+private:
+ String maText;
+ SvMemoryStream maHTMLStream;
+
+public:
+ TETextDataObject( const String& rText );
+ ~TETextDataObject();
+
+ String& GetText() { return maText; }
+ SvMemoryStream& GetHTMLStream() { return maHTMLStream; }
+
+ // ::com::sun::star::uno::XInterface
+ ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
+ void SAL_CALL acquire() throw() { OWeakObject::acquire(); }
+ void SAL_CALL release() throw() { OWeakObject::release(); }
+
+ // ::com::sun::star::datatransfer::XTransferable
+ ::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);
+ ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException);
+ sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException);
+};
+
+TETextDataObject::TETextDataObject( const String& rText ) : maText( rText )
+{
+}
+
+TETextDataObject::~TETextDataObject()
+{
+}
+
+// uno::XInterface
+uno::Any TETextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException)
+{
+ uno::Any aRet = ::cppu::queryInterface( rType, (static_cast< datatransfer::XTransferable* >(this)) );
+ return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
+}
+
+// datatransfer::XTransferable
+uno::Any TETextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException)
+{
+ uno::Any aAny;
+
+ sal_uLong nT = SotExchange::GetFormat( rFlavor );
+ if ( nT == SOT_FORMAT_STRING )
+ {
+ aAny <<= (::rtl::OUString)GetText();
+ }
+ else if ( nT == SOT_FORMATSTR_ID_HTML )
+ {
+ GetHTMLStream().Seek( STREAM_SEEK_TO_END );
+ sal_uLong nLen = GetHTMLStream().Tell();
+ GetHTMLStream().Seek(0);
+
+ uno::Sequence< sal_Int8 > aSeq( nLen );
+ memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen );
+ aAny <<= aSeq;
+ }
+ else
+ {
+ throw datatransfer::UnsupportedFlavorException();
+ }
+ return aAny;
+}
+
+uno::Sequence< datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException)
+{
+ GetHTMLStream().Seek( STREAM_SEEK_TO_END );
+ sal_Bool bHTML = GetHTMLStream().Tell() > 0;
+ uno::Sequence< datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 );
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] );
+ if ( bHTML )
+ SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_HTML, aDataFlavors.getArray()[1] );
+ return aDataFlavors;
+}
+
+sal_Bool TETextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException)
+{
+ sal_uLong nT = SotExchange::GetFormat( rFlavor );
+ return ( nT == SOT_FORMAT_STRING );
+}
+
+struct ImpTextView
+{
+ TextEngine* mpTextEngine;
+
+ Window* mpWindow;
+ TextSelection maSelection;
+ Point maStartDocPos;
+// TextPaM maMBDownPaM;
+
+ Cursor* mpCursor;
+
+ TextDDInfo* mpDDInfo;
+
+ VirtualDevice* mpVirtDev;
+
+ SelectionEngine* mpSelEngine;
+ TextSelFunctionSet* mpSelFuncSet;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener;
+
+ sal_uInt16 mnTravelXPos;
+
+ sal_Bool mbAutoScroll : 1;
+ sal_Bool mbInsertMode : 1;
+ sal_Bool mbReadOnly : 1;
+ sal_Bool mbPaintSelection : 1;
+ sal_Bool mbAutoIndent : 1;
+ sal_Bool mbHighlightSelection : 1;
+ sal_Bool mbCursorEnabled : 1;
+ sal_Bool mbClickedInSelection : 1;
+ sal_Bool mbSupportProtectAttribute : 1;
+ bool mbCursorAtEndOfLine;
+};
+
+// -------------------------------------------------------------------------
+// (+) class TextView
+// -------------------------------------------------------------------------
+TextView::TextView( TextEngine* pEng, Window* pWindow ) :
+ mpImpl(new ImpTextView)
+{
+ pWindow->EnableRTL( sal_False );
+
+ mpImpl->mpWindow = pWindow;
+ mpImpl->mpTextEngine = pEng;
+ mpImpl->mpVirtDev = NULL;
+
+ mpImpl->mbPaintSelection = sal_True;
+ mpImpl->mbAutoScroll = sal_True;
+ mpImpl->mbInsertMode = sal_True;
+ mpImpl->mbReadOnly = sal_False;
+ mpImpl->mbHighlightSelection = sal_False;
+ mpImpl->mbAutoIndent = sal_False;
+ mpImpl->mbCursorEnabled = sal_True;
+ mpImpl->mbClickedInSelection = sal_False;
+ mpImpl->mbSupportProtectAttribute = sal_False;
+ mpImpl->mbCursorAtEndOfLine = false;
+// mbInSelection = sal_False;
+
+ mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
+
+ mpImpl->mpSelFuncSet = new TextSelFunctionSet( this );
+ mpImpl->mpSelEngine = new SelectionEngine( mpImpl->mpWindow, mpImpl->mpSelFuncSet );
+ mpImpl->mpSelEngine->SetSelectionMode( RANGE_SELECTION );
+ mpImpl->mpSelEngine->EnableDrag( sal_True );
+
+ mpImpl->mpCursor = new Cursor;
+ mpImpl->mpCursor->Show();
+ pWindow->SetCursor( mpImpl->mpCursor );
+ pWindow->SetInputContext( InputContext( pEng->GetFont(), INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT ) );
+
+ if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT )
+ mpImpl->mbHighlightSelection = sal_True;
+
+ pWindow->SetLineColor();
+
+ mpImpl->mpDDInfo = NULL;
+
+ if ( pWindow->GetDragGestureRecognizer().is() )
+ {
+ vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
+ mpImpl->mxDnDListener = pDnDWrapper;
+
+ uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, uno::UNO_QUERY );
+ pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL );
+ uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY );
+ pWindow->GetDropTarget()->addDropTargetListener( xDTL );
+ pWindow->GetDropTarget()->setActive( sal_True );
+ pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
+ }
+}
+
+TextView::~TextView()
+{
+ delete mpImpl->mpSelEngine;
+ delete mpImpl->mpSelFuncSet;
+ delete mpImpl->mpVirtDev;
+
+ if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor )
+ mpImpl->mpWindow->SetCursor( 0 );
+ delete mpImpl->mpCursor;
+ delete mpImpl->mpDDInfo;
+ delete mpImpl;
+}
+
+void TextView::Invalidate()
+{
+ mpImpl->mpWindow->Invalidate();
+}
+
+void TextView::SetSelection( const TextSelection& rTextSel, sal_Bool bGotoCursor )
+{
+ // Falls jemand gerade ein leeres Attribut hinterlassen hat,
+ // und dann der Outliner die Selektion manipulitert:
+ if ( !mpImpl->maSelection.HasRange() )
+ mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() );
+
+ // Wenn nach einem KeyInput die Selection manipuliert wird:
+ mpImpl->mpTextEngine->CheckIdleFormatter();
+
+ HideSelection();
+ TextSelection aNewSel( rTextSel );
+ mpImpl->mpTextEngine->ValidateSelection( aNewSel );
+ ImpSetSelection( aNewSel );
+ ShowSelection();
+ ShowCursor( bGotoCursor );
+}
+
+void TextView::SetSelection( const TextSelection& rTextSel )
+{
+ SetSelection( rTextSel, mpImpl->mbAutoScroll );
+}
+
+const TextSelection& TextView::GetSelection() const
+{
+ return mpImpl->maSelection;
+}
+TextSelection& TextView::GetSelection()
+{
+ return mpImpl->maSelection;
+}
+
+void TextView::DeleteSelected()
+{
+// HideSelection();
+
+ mpImpl->mpTextEngine->UndoActionStart();
+ TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
+ mpImpl->mpTextEngine->UndoActionEnd();
+
+ ImpSetSelection( aPaM );
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+ ShowCursor();
+}
+
+void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection )
+{
+ if ( !mpImpl->mbPaintSelection )
+ pSelection = NULL;
+ else
+ {
+ // Richtige Hintergrundfarbe einstellen.
+ // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat.
+ Font aFont = mpImpl->mpTextEngine->GetFont();
+ Color aColor = pOut->GetBackground().GetColor();
+ aColor.SetTransparency( 0 );
+ if ( aColor != aFont.GetFillColor() )
+ {
+ if( aFont.IsTransparent() )
+ aColor = Color( COL_TRANSPARENT );
+ aFont.SetFillColor( aColor );
+ mpImpl->mpTextEngine->maFont = aFont;
+ }
+ }
+
+ mpImpl->mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection );
+}
+
+void TextView::Paint( const Rectangle& rRect )
+{
+ ImpPaint( rRect, sal_False );
+}
+
+void TextView::ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev )
+{
+ if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() )
+ return;
+
+ TextSelection *pDrawSelection = NULL;
+ if ( !mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange() )
+ pDrawSelection = &mpImpl->maSelection;
+
+ if ( bUseVirtDev )
+ {
+ VirtualDevice* pVDev = GetVirtualDevice();
+
+ const Color& rBackgroundColor = mpImpl->mpWindow->GetBackground().GetColor();
+ if ( pVDev->GetFillColor() != rBackgroundColor )
+ pVDev->SetFillColor( rBackgroundColor );
+ if ( pVDev->GetBackground().GetColor() != rBackgroundColor )
+ pVDev->SetBackground( rBackgroundColor );
+
+ sal_Bool bVDevValid = sal_True;
+ Size aOutSz( pVDev->GetOutputSizePixel() );
+ if ( ( aOutSz.Width() < rRect.GetWidth() ) ||
+ ( aOutSz.Height() < rRect.GetHeight() ) )
+ {
+ bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() );
+ }
+ else
+ {
+ // Das VirtDev kann bei einem Resize sehr gross werden =>
+ // irgendwann mal kleiner machen!
+ if ( ( aOutSz.Height() > ( rRect.GetHeight() + 20 ) ) ||
+ ( aOutSz.Width() > ( rRect.GetWidth() + 20 ) ) )
+ {
+ bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() );
+ }
+ else
+ {
+ pVDev->Erase();
+ }
+ }
+ if ( !bVDevValid )
+ {
+ ImpPaint( rRect, sal_False /* ohne VDev */ );
+ return;
+ }
+
+ Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() );
+
+ Point aDocPos( mpImpl->maStartDocPos.X(), mpImpl->maStartDocPos.Y() + rRect.Top() );
+ Point aStartPos = ImpGetOutputStartPos( aDocPos );
+ ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pDrawSelection );
+ mpImpl->mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(),
+ Point(0,0), rRect.GetSize(), *pVDev );
+// ShowSelection();
+ if ( mpImpl->mbHighlightSelection )
+ ImpHighlight( mpImpl->maSelection );
+ }
+ else
+ {
+ Point aStartPos = ImpGetOutputStartPos( mpImpl->maStartDocPos );
+ ImpPaint( mpImpl->mpWindow, aStartPos, &rRect, NULL, pDrawSelection );
+
+// ShowSelection();
+ if ( mpImpl->mbHighlightSelection )
+ ImpHighlight( mpImpl->maSelection );
+ }
+}
+
+void TextView::ImpHighlight( const TextSelection& rSel )
+{
+ TextSelection aSel( rSel );
+ aSel.Justify();
+ if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() )
+ {
+ mpImpl->mpCursor->Hide();
+
+ DBG_ASSERT( !mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" );
+
+ Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() );
+ long nY = 0;
+ sal_uLong nStartPara = aSel.GetStart().GetPara();
+ sal_uLong nEndPara = aSel.GetEnd().GetPara();
+ for ( sal_uLong nPara = 0; nPara <= nEndPara; nPara++ )
+ {
+ long nParaHeight = (long)mpImpl->mpTextEngine->CalcParaHeight( nPara );
+ if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) )
+ {
+ TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara );
+ sal_uInt16 nStartLine = 0;
+ sal_uInt16 nEndLine = pTEParaPortion->GetLines().size() -1;
+ if ( nPara == nStartPara )
+ nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), sal_False );
+ if ( nPara == nEndPara )
+ nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), sal_True );
+
+ // ueber die Zeilen iterieren....
+ for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ )
+ {
+ TextLine* pLine = pTEParaPortion->GetLines()[ nLine ];
+ sal_uInt16 nStartIndex = pLine->GetStart();
+ sal_uInt16 nEndIndex = pLine->GetEnd();
+ if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) )
+ nStartIndex = aSel.GetStart().GetIndex();
+ if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) )
+ nEndIndex = aSel.GetEnd().GetIndex();
+
+ // Kann passieren, wenn am Anfang einer umgebrochenen Zeile.
+ if ( nEndIndex < nStartIndex )
+ nEndIndex = nStartIndex;
+
+ Rectangle aTmpRec( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), sal_False ) );
+ aTmpRec.Top() += nY;
+ aTmpRec.Bottom() += nY;
+ Point aTopLeft( aTmpRec.TopLeft() );
+
+ aTmpRec = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), sal_True );
+ aTmpRec.Top() += nY;
+ aTmpRec.Bottom() += nY;
+ Point aBottomRight( aTmpRec.BottomRight() );
+ aBottomRight.X()--;
+
+ // Nur Painten, wenn im sichtbaren Bereich...
+ if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) )
+ {
+ Point aPnt1( GetWindowPos( aTopLeft ) );
+ Point aPnt2( GetWindowPos( aBottomRight ) );
+
+ Rectangle aRect( aPnt1, aPnt2 );
+ mpImpl->mpWindow->Invert( aRect );
+ }
+ }
+ }
+ nY += nParaHeight;
+
+ if ( nY >= aVisArea.Bottom() )
+ break;
+ }
+ }
+}
+
+void TextView::ImpSetSelection( const TextSelection& rSelection )
+{
+ if ( rSelection != mpImpl->maSelection )
+ {
+ mpImpl->maSelection = rSelection;
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSELECTIONCHANGED ) );
+ }
+}
+
+void TextView::ShowSelection()
+{
+ ImpShowHideSelection( sal_True );
+}
+
+void TextView::HideSelection()
+{
+ ImpShowHideSelection( sal_False );
+}
+
+void TextView::ShowSelection( const TextSelection& rRange )
+{
+ ImpShowHideSelection( sal_True, &rRange );
+}
+
+void TextView::ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange )
+{
+ const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection;
+
+ if ( pRangeOrSelection->HasRange() )
+ {
+ if ( mpImpl->mbHighlightSelection )
+ {
+ ImpHighlight( *pRangeOrSelection );
+ }
+ else
+ {
+ if( mpImpl->mpWindow->IsPaintTransparent() )
+ mpImpl->mpWindow->Invalidate();
+ else
+ {
+ Rectangle aOutArea( Point( 0, 0 ), mpImpl->mpWindow->GetOutputSizePixel() );
+ Point aStartPos( ImpGetOutputStartPos( mpImpl->maStartDocPos ) );
+ TextSelection aRange( *pRangeOrSelection );
+ aRange.Justify();
+ sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible();
+ mpImpl->mpCursor->Hide();
+ ImpPaint( mpImpl->mpWindow, aStartPos, &aOutArea, &aRange, bShow ? &mpImpl->maSelection : NULL );
+ if ( bVisCursor )
+ mpImpl->mpCursor->Show();
+ }
+ }
+ }
+}
+
+VirtualDevice* TextView::GetVirtualDevice()
+{
+ if ( !mpImpl->mpVirtDev )
+ {
+ mpImpl->mpVirtDev = new VirtualDevice;
+ mpImpl->mpVirtDev->SetLineColor();
+ }
+ return mpImpl->mpVirtDev;
+}
+
+void TextView::EraseVirtualDevice()
+{
+ delete mpImpl->mpVirtDev;
+ mpImpl->mpVirtDev = 0;
+}
+
+sal_Bool TextView::KeyInput( const KeyEvent& rKeyEvent )
+{
+ sal_Bool bDone = sal_True;
+ sal_Bool bModified = sal_False;
+ sal_Bool bMoved = sal_False;
+ sal_Bool bEndKey = sal_False; // spezielle CursorPosition
+ sal_Bool bAllowIdle = sal_True;
+
+ // Um zu pruefen ob durch irgendeine Aktion mModified, das lokale
+ // bModified wird z.B. bei Cut/Paste nicht gesetzt, weil dort an anderen
+ // Stellen das updaten erfolgt.
+ sal_Bool bWasModified = mpImpl->mpTextEngine->IsModified();
+ mpImpl->mpTextEngine->SetModified( sal_False );
+
+ TextSelection aCurSel( mpImpl->maSelection );
+ TextSelection aOldSel( aCurSel );
+
+ sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode();
+ KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
+ if ( eFunc != KEYFUNC_DONTKNOW )
+ {
+ switch ( eFunc )
+ {
+ case KEYFUNC_CUT:
+ {
+ if ( !mpImpl->mbReadOnly )
+ Cut();
+ }
+ break;
+ case KEYFUNC_COPY:
+ {
+ Copy();
+ }
+ break;
+ case KEYFUNC_PASTE:
+ {
+ if ( !mpImpl->mbReadOnly )
+ Paste();
+ }
+ break;
+ case KEYFUNC_UNDO:
+ {
+ if ( !mpImpl->mbReadOnly )
+ Undo();
+ }
+ break;
+ case KEYFUNC_REDO:
+ {
+ if ( !mpImpl->mbReadOnly )
+ Redo();
+ }
+ break;
+
+ default: // wird dann evtl. unten bearbeitet.
+ eFunc = KEYFUNC_DONTKNOW;
+ }
+ }
+ if ( eFunc == KEYFUNC_DONTKNOW )
+ {
+ switch ( nCode )
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_HOME:
+ case KEY_END:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN:
+ case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
+ case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
+ case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
+ case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
+ {
+ if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) )
+ && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) )
+ {
+ aCurSel = ImpMoveCursor( rKeyEvent );
+ if ( aCurSel.HasRange() ) {
+ uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
+ Copy( aSelection );
+ }
+ bMoved = sal_True;
+ if ( nCode == KEY_END )
+ bEndKey = sal_True;
+ }
+ else
+ bDone = sal_False;
+ }
+ break;
+ case KEY_BACKSPACE:
+ case KEY_DELETE:
+ case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
+ case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
+ case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
+ case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
+ {
+ if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() )
+ {
+ sal_uInt8 nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT;
+ sal_uInt8 nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE;
+ if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() )
+ nMode = DELMODE_RESTOFCONTENT;
+
+ switch( nCode )
+ {
+ case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
+ nDel = DEL_LEFT;
+ nMode = DELMODE_RESTOFWORD;
+ break;
+ case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
+ nDel = DEL_RIGHT;
+ nMode = DELMODE_RESTOFWORD;
+ break;
+ case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
+ nDel = DEL_LEFT;
+ nMode = DELMODE_RESTOFCONTENT;
+ break;
+ case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
+ nDel = DEL_RIGHT;
+ nMode = DELMODE_RESTOFCONTENT;
+ break;
+ default: break;
+ }
+
+ mpImpl->mpTextEngine->UndoActionStart();
+ if(mpImpl->mbSupportProtectAttribute)
+ {
+ //expand selection to include all protected content - if there is any
+ const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
+ TextPaM(mpImpl->maSelection.GetStart().GetPara(),
+ mpImpl->maSelection.GetStart().GetIndex()),
+ TEXTATTR_PROTECTED );
+ const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
+ TextPaM(mpImpl->maSelection.GetEnd().GetPara(),
+ mpImpl->maSelection.GetEnd().GetIndex()),
+ TEXTATTR_PROTECTED );
+ if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex())
+ {
+ mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart();
+ }
+ if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex())
+ {
+ mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd();
+ }
+ }
+ aCurSel = ImpDelete( nDel, nMode );
+ mpImpl->mpTextEngine->UndoActionEnd();
+ bModified = sal_True;
+ bAllowIdle = sal_False;
+ }
+ else
+ bDone = sal_False;
+ }
+ break;
+ case KEY_TAB:
+ {
+ if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() &&
+ !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() &&
+ ImplCheckTextLen( rtl::OUString('x') ) )
+ {
+ aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() );
+ bModified = sal_True;
+ }
+ else
+ bDone = sal_False;
+ }
+ break;
+ case KEY_RETURN:
+ {
+ // Shift-RETURN darf nicht geschluckt werden, weil dann keine
+ // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich.
+ if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() &&
+ !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( rtl::OUString('x') ) )
+ {
+ mpImpl->mpTextEngine->UndoActionStart();
+ aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel );
+ if ( mpImpl->mbAutoIndent )
+ {
+ TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 );
+ sal_uInt16 n = 0;
+ while ( ( n < pPrev->GetText().Len() ) && (
+ ( pPrev->GetText().GetChar( n ) == ' ' ) ||
+ ( pPrev->GetText().GetChar( n ) == '\t' ) ) )
+ {
+ n++;
+ }
+ if ( n )
+ aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) );
+ }
+ mpImpl->mpTextEngine->UndoActionEnd();
+ bModified = sal_True;
+ }
+ else
+ bDone = sal_False;
+ }
+ break;
+ case KEY_INSERT:
+ {
+ if ( !mpImpl->mbReadOnly )
+ SetInsertMode( !IsInsertMode() );
+ }
+ break;
+ default:
+ {
+ if ( TextEngine::IsSimpleCharInput( rKeyEvent ) )
+ {
+ xub_Unicode nCharCode = rKeyEvent.GetCharCode();
+ if ( !mpImpl->mbReadOnly && ImplCheckTextLen( rtl::OUString(nCharCode) ) ) // sonst trotzdem das Zeichen schlucken...
+ {
+ aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True );
+ bModified = sal_True;
+ }
+ }
+ else
+ bDone = sal_False;
+ }
+ }
+ }
+
+ if ( aCurSel != aOldSel ) // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that!
+ ImpSetSelection( aCurSel );
+
+ mpImpl->mpTextEngine->UpdateSelections();
+
+ if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) )
+ mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
+
+ if ( bModified )
+ {
+ // Idle-Formatter nur, wenn AnyInput.
+ if ( bAllowIdle && Application::AnyInput( VCL_INPUT_KEYBOARD) )
+ mpImpl->mpTextEngine->IdleFormatAndUpdate( this );
+ else
+ mpImpl->mpTextEngine->FormatAndUpdate( this);
+ }
+ else if ( bMoved )
+ {
+ // Selection wird jetzt gezielt in ImpMoveCursor gemalt.
+ ImpShowCursor( mpImpl->mbAutoScroll, sal_True, bEndKey );
+ }
+
+ if ( mpImpl->mpTextEngine->IsModified() )
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ else if ( bWasModified )
+ mpImpl->mpTextEngine->SetModified( sal_True );
+
+ return bDone;
+}
+
+void TextView::MouseButtonUp( const MouseEvent& rMouseEvent )
+{
+ mpImpl->mbClickedInSelection = sal_False;
+ mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
+ mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent );
+ if ( rMouseEvent.IsMiddle() && !IsReadOnly() &&
+ ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
+ {
+ uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
+ Paste( aSelection );
+ if ( mpImpl->mpTextEngine->IsModified() )
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ }
+ else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() )
+ {
+ uno::Reference<datatransfer::clipboard::XClipboard> aSelection(GetWindow()->GetPrimarySelection());
+ Copy( aSelection );
+ }
+}
+
+void TextView::MouseButtonDown( const MouseEvent& rMouseEvent )
+{
+ mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown
+ mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
+ mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
+
+ mpImpl->mpTextEngine->SetActiveView( this );
+
+ mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent );
+
+ // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed'
+ // notification. The appropriate handler could change the current selection,
+ // which is the case in the MailMerge address block control. To enable select'n'drag
+ // we need to reevaluate the selection after the notification has been fired.
+ mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
+
+ // Sonderbehandlungen
+ if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) )
+ {
+ if ( rMouseEvent.IsMod2() )
+ {
+ HideSelection();
+ ImpSetSelection( mpImpl->maSelection.GetEnd() );
+ SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // Wird von SelectionEngine bei MOD2 nicht gesetzt
+ }
+
+ if ( rMouseEvent.GetClicks() == 2 )
+ {
+ // Wort selektieren
+ if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) )
+ {
+ HideSelection();
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() );
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ TextSelection aNewSel( mpImpl->maSelection );
+ aNewSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos;
+ aNewSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos;
+ if(mpImpl->mbSupportProtectAttribute)
+ {
+ //expand selection to include all protected content - if there is any
+ const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
+ TextPaM(aNewSel.GetStart().GetPara(),
+ (sal_uInt16)aBoundary.startPos),
+ TEXTATTR_PROTECTED );
+ const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
+ TextPaM(aNewSel.GetEnd().GetPara(),
+ (sal_uInt16)aBoundary.endPos),
+ TEXTATTR_PROTECTED );
+ if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex())
+ {
+ aNewSel.GetStart().GetIndex() = pStartAttr->GetStart();
+ }
+ if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex())
+ {
+ aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd();
+ }
+ }
+ ImpSetSelection( aNewSel );
+ ShowSelection();
+ ShowCursor( sal_True, sal_True );
+ }
+ }
+ else if ( rMouseEvent.GetClicks() == 3 )
+ {
+ // Absatz selektieren
+ if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) )
+ {
+ HideSelection();
+ TextSelection aNewSel( mpImpl->maSelection );
+ aNewSel.GetStart().GetIndex() = 0;
+ aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() )->GetText().Len();
+ ImpSetSelection( aNewSel );
+ ShowSelection();
+ ShowCursor( sal_True, sal_True );
+ }
+ }
+ }
+}
+
+
+void TextView::MouseMove( const MouseEvent& rMouseEvent )
+{
+ mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW;
+ mpImpl->mpSelEngine->SelMouseMove( rMouseEvent );
+}
+
+void TextView::Command( const CommandEvent& rCEvt )
+{
+ mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown
+ mpImpl->mpTextEngine->SetActiveView( this );
+
+ if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
+ {
+ DeleteSelected();
+ delete mpImpl->mpTextEngine->mpIMEInfos;
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( GetSelection().GetEnd().GetPara() );
+ mpImpl->mpTextEngine->mpIMEInfos = new TEIMEInfos( GetSelection().GetEnd(), pNode->GetText().Copy( GetSelection().GetEnd().GetIndex() ) );
+ mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
+ {
+ DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" );
+ if( mpImpl->mpTextEngine->mpIMEInfos )
+ {
+ TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() );
+ pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 );
+
+ sal_Bool bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite;
+
+ delete mpImpl->mpTextEngine->mpIMEInfos;
+ mpImpl->mpTextEngine->mpIMEInfos = NULL;
+
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+
+ SetInsertMode( bInsertMode );
+
+ if ( mpImpl->mpTextEngine->IsModified() )
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ }
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
+ {
+ DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" );
+ if( mpImpl->mpTextEngine->mpIMEInfos )
+ {
+ const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
+
+ if ( !pData->IsOnlyCursorChanged() )
+ {
+ TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos );
+ aSelect.GetEnd().GetIndex() = aSelect.GetEnd().GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen;
+ aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect );
+ aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() );
+
+ if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite )
+ {
+ sal_uInt16 nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen;
+ sal_uInt16 nNewIMETextLen = pData->GetText().Len();
+
+ if ( ( nOldIMETextLen > nNewIMETextLen ) &&
+ ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
+ {
+ // restore old characters
+ sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen;
+ TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos );
+ aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen;
+ mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) );
+ }
+ else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
+ ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
+ {
+ // overwrite
+ sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen;
+ if ( ( nOldIMETextLen + nOverwrite ) > mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() )
+ nOverwrite = mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen;
+ DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" );
+ TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos );
+ aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen;
+ TextSelection aSel( aPaM );
+ aSel.GetEnd().GetIndex() =
+ aSel.GetEnd().GetIndex() + nOverwrite;
+ mpImpl->mpTextEngine->ImpDeleteText( aSel );
+ }
+ }
+
+ if ( pData->GetTextAttr() )
+ {
+ mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
+ mpImpl->mpTextEngine->mpIMEInfos->bCursor = pData->IsCursorVisible();
+ }
+ else
+ {
+ mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs();
+ }
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() );
+ pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 );
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+ }
+
+ TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() );
+ SetSelection( aNewSel );
+ SetInsertMode( !pData->IsCursorOverwrite() );
+
+ if ( pData->IsCursorVisible() )
+ ShowCursor();
+ else
+ HideCursor();
+ }
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
+ {
+ if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen )
+ {
+ TextPaM aPaM( GetSelection().GetEnd() );
+ Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM );
+
+ sal_uInt16 nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen;
+
+ if ( !mpImpl->mpTextEngine->IsFormatted() )
+ mpImpl->mpTextEngine->FormatDoc();
+
+ TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True );
+ TextLine* pLine = pParaPortion->GetLines()[ nLine ];
+ if ( pLine && ( nInputEnd > pLine->GetEnd() ) )
+ nInputEnd = pLine->GetEnd();
+ Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) );
+
+ long nWidth = aR2.Left()-aR1.Right();
+ aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() );
+ GetWindow()->SetCursorRect( &aR1, nWidth );
+ }
+ else
+ {
+ GetWindow()->SetCursorRect();
+ }
+ }
+ else
+ {
+ mpImpl->mpSelEngine->Command( rCEvt );
+ }
+}
+
+void TextView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor )
+{
+ // Die Einstellung hat mehr Gewicht:
+ if ( !mpImpl->mbAutoScroll )
+ bGotoCursor = sal_False;
+ ImpShowCursor( bGotoCursor, bForceVisCursor, sal_False );
+}
+
+void TextView::HideCursor()
+{
+ mpImpl->mpCursor->Hide();
+}
+
+void TextView::Scroll( long ndX, long ndY )
+{
+ DBG_ASSERT( mpImpl->mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" );
+
+ if ( !ndX && !ndY )
+ return;
+
+ Point aNewStartPos( mpImpl->maStartDocPos );
+
+ // Vertical:
+ aNewStartPos.Y() -= ndY;
+ if ( aNewStartPos.Y() < 0 )
+ aNewStartPos.Y() = 0;
+
+ // Horizontal:
+ aNewStartPos.X() -= ndX;
+ if ( aNewStartPos.X() < 0 )
+ aNewStartPos.X() = 0;
+
+ long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X();
+ long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y();
+
+ if ( nDiffX || nDiffY )
+ {
+ sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible();
+ mpImpl->mpCursor->Hide();
+ mpImpl->mpWindow->Update();
+ mpImpl->maStartDocPos = aNewStartPos;
+
+ if ( mpImpl->mpTextEngine->IsRightToLeft() )
+ nDiffX = -nDiffX;
+ mpImpl->mpWindow->Scroll( nDiffX, nDiffY );
+ mpImpl->mpWindow->Update();
+ mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) );
+ if ( bVisCursor && !mpImpl->mbReadOnly )
+ mpImpl->mpCursor->Show();
+ }
+
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) );
+}
+
+void TextView::Undo()
+{
+ mpImpl->mpTextEngine->SetActiveView( this );
+ mpImpl->mpTextEngine->GetUndoManager().Undo();
+}
+
+void TextView::Redo()
+{
+ mpImpl->mpTextEngine->SetActiveView( this );
+ mpImpl->mpTextEngine->GetUndoManager().Redo();
+}
+
+void TextView::Cut()
+{
+ mpImpl->mpTextEngine->UndoActionStart();
+ Copy();
+ DeleteSelected();
+ mpImpl->mpTextEngine->UndoActionEnd();
+}
+
+void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
+{
+ if ( rxClipboard.is() )
+ {
+ TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
+
+ if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML
+ mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True );
+
+ const sal_uInt32 nRef = Application::ReleaseSolarMutex();
+
+ try
+ {
+ rxClipboard->setContents( pDataObj, NULL );
+
+ uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
+ if( xFlushableClipboard.is() )
+ xFlushableClipboard->flushClipboard();
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+
+ Application::AcquireSolarMutex( nRef );
+ }
+}
+
+void TextView::Copy()
+{
+ uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard());
+ Copy( aClipboard );
+}
+
+void TextView::Paste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
+{
+ if ( rxClipboard.is() )
+ {
+ uno::Reference< datatransfer::XTransferable > xDataObj;
+
+ const sal_uInt32 nRef = Application::ReleaseSolarMutex();
+
+ try
+ {
+ xDataObj = rxClipboard->getContents();
+ }
+ catch( const ::com::sun::star::uno::Exception& )
+ {
+ }
+
+ Application::AcquireSolarMutex( nRef );
+
+ if ( xDataObj.is() )
+ {
+ datatransfer::DataFlavor aFlavor;
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
+ if ( xDataObj->isDataFlavorSupported( aFlavor ) )
+ {
+ try
+ {
+ uno::Any aData = xDataObj->getTransferData( aFlavor );
+ ::rtl::OUString aText;
+ aData >>= aText;
+ bool bWasTruncated = false;
+ if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 )
+ bWasTruncated = ImplTruncateNewText( aText );
+ InsertNewText( aText, sal_False );
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+
+ if( bWasTruncated )
+ Edit::ShowTruncationWarning( mpImpl->mpWindow );
+ }
+ catch( const ::com::sun::star::datatransfer::UnsupportedFlavorException& )
+ {
+ }
+ }
+ }
+ }
+}
+
+void TextView::Paste()
+{
+ uno::Reference<datatransfer::clipboard::XClipboard> aClipboard(GetWindow()->GetClipboard());
+ Paste( aClipboard );
+}
+
+String TextView::GetSelected()
+{
+ return GetSelected( GetSystemLineEnd() );
+}
+
+String TextView::GetSelected( LineEnd aSeparator )
+{
+ return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator );
+}
+
+void TextView::SetInsertMode( sal_Bool bInsert )
+{
+ if ( mpImpl->mbInsertMode != bInsert )
+ {
+ mpImpl->mbInsertMode = bInsert;
+ ShowCursor( mpImpl->mbAutoScroll, sal_False );
+ }
+}
+
+void TextView::SetReadOnly( sal_Bool bReadOnly )
+{
+ if ( mpImpl->mbReadOnly != bReadOnly )
+ {
+ mpImpl->mbReadOnly = bReadOnly;
+ if ( !mpImpl->mbReadOnly )
+ ShowCursor( mpImpl->mbAutoScroll, sal_False );
+ else
+ HideCursor();
+
+ GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
+ }
+}
+
+TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent )
+{
+ // Eigentlich nur bei Up/Down noetig, aber was solls.
+ mpImpl->mpTextEngine->CheckIdleFormatter();
+
+ TextPaM aPaM( mpImpl->maSelection.GetEnd() );
+ TextPaM aOldEnd( aPaM );
+
+ TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom;
+ if ( mpImpl->mpTextEngine->IsRightToLeft() )
+ eTextDirection = TextDirectionality_RightToLeft_TopToBottom;
+
+ KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection );
+
+ sal_Bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? sal_True : sal_False;
+ sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode();
+
+ bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift();
+ switch ( nCode )
+ {
+ case KEY_UP: aPaM = CursorUp( aPaM );
+ break;
+ case KEY_DOWN: aPaM = CursorDown( aPaM );
+ break;
+ case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM );
+ break;
+ case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM );
+ break;
+ case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM );
+ break;
+ case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM );
+ break;
+ case KEY_LEFT: aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
+ break;
+ case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
+ break;
+ case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
+ bSelect = true; // fallthrough intentional
+ case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
+ aPaM = CursorWordRight( aPaM );
+ break;
+ case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
+ bSelect = true; // fallthrough intentional
+ case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
+ aPaM = CursorWordLeft( aPaM );
+ break;
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
+ bSelect = true; // fallthrough intentional
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
+ aPaM = CursorStartOfLine( aPaM );
+ break;
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
+ bSelect = true; // fallthrough intentional
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
+ aPaM = CursorEndOfLine( aPaM );
+ break;
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
+ bSelect = true; // falltthrough intentional
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
+ aPaM = CursorStartOfParagraph( aPaM );
+ break;
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
+ bSelect = true; // falltthrough intentional
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
+ aPaM = CursorEndOfParagraph( aPaM );
+ break;
+ case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
+ bSelect = true; // falltthrough intentional
+ case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
+ aPaM = CursorStartOfDoc();
+ break;
+ case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
+ bSelect = true; // falltthrough intentional
+ case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
+ aPaM = CursorEndOfDoc();
+ break;
+ }
+
+ // Bewirkt evtl. ein CreateAnchor oder Deselection all
+ mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
+
+ if ( aOldEnd != aPaM )
+ {
+ mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() );
+
+ TextSelection aNewSelection( mpImpl->maSelection );
+ aNewSelection.GetEnd() = aPaM;
+ if ( bSelect )
+ {
+ // Dann wird die Selektion erweitert...
+ ImpSetSelection( aNewSelection );
+ ShowSelection( TextSelection( aOldEnd, aPaM ) );
+ }
+ else
+ {
+ aNewSelection.GetStart() = aPaM;
+ ImpSetSelection( aNewSelection );
+ }
+ }
+
+ return mpImpl->maSelection;
+}
+
+void TextView::InsertText( const XubString& rStr, sal_Bool bSelect )
+{
+ InsertNewText( rStr, bSelect );
+}
+
+void TextView::InsertNewText( const rtl::OUString& rStr, sal_Bool bSelect )
+{
+// HideSelection();
+ mpImpl->mpTextEngine->UndoActionStart();
+
+ /* #i87633#
+ break inserted text into chunks that fit into the underlying String
+ based API (which has a maximum length of 65534 elements
+
+ note: this will of course still cause problems for lines longer than those
+ 65534 elements, but those cases will hopefully be few.
+ In the long run someone should switch the TextEngine to OUString instead of String
+ */
+ sal_Int32 nLen = rStr.getLength();
+ sal_Int32 nPos = 0;
+ do
+ {
+ sal_Int32 nChunkLen = nLen > 65534 ? 65534 : nLen;
+ String aChunk( rStr.copy( nPos, nChunkLen ) );
+
+ TextSelection aNewSel( mpImpl->maSelection );
+
+ TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, aChunk );
+
+ if ( bSelect )
+ {
+ aNewSel.Justify();
+ aNewSel.GetEnd() = aPaM;
+ }
+ else
+ {
+ aNewSel = aPaM;
+ }
+
+ ImpSetSelection( aNewSel );
+ nLen -= nChunkLen;
+ nPos += nChunkLen;
+ }
+ while( nLen );
+
+ mpImpl->mpTextEngine->UndoActionEnd();
+
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+}
+
+TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode )
+{
+ TextPaM aPaM( rPaM );
+
+ if ( aPaM.GetIndex() )
+ {
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ sal_Int32 nCount = 1;
+ aPaM.GetIndex() = (sal_uInt16)xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount );
+ }
+ else if ( aPaM.GetPara() )
+ {
+ aPaM.GetPara()--;
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ aPaM.GetIndex() = pNode->GetText().Len();
+ }
+ return aPaM;
+}
+
+TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode )
+{
+ TextPaM aPaM( rPaM );
+
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ if ( aPaM.GetIndex() < pNode->GetText().Len() )
+ {
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ sal_Int32 nCount = 1;
+ aPaM.GetIndex() = (sal_uInt16)xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount );
+ }
+ else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
+ {
+ aPaM.GetPara()++;
+ aPaM.GetIndex() = 0;
+ }
+
+ return aPaM;
+}
+
+
+TextPaM TextView::CursorWordLeft( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ if ( aPaM.GetIndex() )
+ {
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ if ( aBoundary.startPos >= rPaM.GetIndex() )
+ aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? (sal_uInt16)aBoundary.startPos : 0;
+ }
+ else if ( aPaM.GetPara() )
+ {
+ aPaM.GetPara()--;
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ aPaM.GetIndex() = pNode->GetText().Len();
+ }
+ return aPaM;
+}
+
+
+TextPaM TextView::CursorWordRight( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ if ( aPaM.GetIndex() < pNode->GetText().Len() )
+ {
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aPaM.GetIndex() = (sal_uInt16)aBoundary.startPos;
+ }
+ else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
+ {
+ aPaM.GetPara()++;
+ aPaM.GetIndex() = 0;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode )
+{
+ if ( mpImpl->maSelection.HasRange() ) // dann nur Sel. loeschen
+ return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
+
+ TextPaM aStartPaM = mpImpl->maSelection.GetStart();
+ TextPaM aEndPaM = aStartPaM;
+ if ( nMode == DEL_LEFT )
+ {
+ if ( nDelMode == DELMODE_SIMPLE )
+ {
+ aEndPaM = CursorLeft( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER );
+ }
+ else if ( nDelMode == DELMODE_RESTOFWORD )
+ {
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() )
+ aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ // #i63506# startPos is -1 when the paragraph starts with a tab
+ aEndPaM.GetIndex() = (aBoundary.startPos >= 0) ? (sal_uInt16)aBoundary.startPos : 0;
+ }
+ else // DELMODE_RESTOFCONTENT
+ {
+ if ( aEndPaM.GetIndex() != 0 )
+ aEndPaM.GetIndex() = 0;
+ else if ( aEndPaM.GetPara() )
+ {
+ // Absatz davor
+ aEndPaM.GetPara()--;
+ aEndPaM.GetIndex() = 0;
+ }
+ }
+ }
+ else
+ {
+ if ( nDelMode == DELMODE_SIMPLE )
+ {
+ aEndPaM = CursorRight( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
+ }
+ else if ( nDelMode == DELMODE_RESTOFWORD )
+ {
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator();
+ i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
+ aEndPaM.GetIndex() = (sal_uInt16)aBoundary.startPos;
+ }
+ else // DELMODE_RESTOFCONTENT
+ {
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ if ( aEndPaM.GetIndex() < pNode->GetText().Len() )
+ aEndPaM.GetIndex() = pNode->GetText().Len();
+ else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) )
+ {
+ // Absatz danach
+ aEndPaM.GetPara()++;
+ TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ aEndPaM.GetIndex() = pNextNode->GetText().Len();
+ }
+ }
+ }
+
+ return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) );
+}
+
+
+
+TextPaM TextView::CursorUp( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ long nX;
+ if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW )
+ {
+ nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left();
+ mpImpl->mnTravelXPos = (sal_uInt16)nX+1;
+ }
+ else
+ nX = mpImpl->mnTravelXPos;
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False );
+ if ( nLine ) // gleicher Absatz
+ {
+ sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX );
+ aPaM.GetIndex() = nCharPos;
+ // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das
+ // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang
+ // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor
+ TextLine* pLine = pPPortion->GetLines()[ nLine - 1 ];
+ if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) )
+ aPaM.GetIndex()--;
+ }
+ else if ( rPaM.GetPara() ) // vorheriger Absatz
+ {
+ aPaM.GetPara()--;
+ pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ sal_uInt16 nL = pPPortion->GetLines().size() - 1;
+ sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 );
+ aPaM.GetIndex() = nCharPos;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::CursorDown( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ long nX;
+ if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW )
+ {
+ nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left();
+ mpImpl->mnTravelXPos = (sal_uInt16)nX+1;
+ }
+ else
+ nX = mpImpl->mnTravelXPos;
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False );
+ if ( nLine < ( pPPortion->GetLines().size() - 1 ) )
+ {
+ sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX );
+ aPaM.GetIndex() = nCharPos;
+
+ // Sonderbehandlung siehe CursorUp...
+ TextLine* pLine = pPPortion->GetLines()[ nLine + 1 ];
+ if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() )
+ aPaM.GetIndex()--;
+ }
+ else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz
+ {
+ aPaM.GetPara()++;
+ pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 );
+ aPaM.GetIndex() = nCharPos;
+ TextLine* pLine = pPPortion->GetLines().front();
+ if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().size() > 1 ) )
+ aPaM.GetIndex()--;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
+ TextLine* pLine = pPPortion->GetLines()[ nLine ];
+ aPaM.GetIndex() = pLine->GetStart();
+
+ return aPaM;
+}
+
+TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
+ TextLine* pLine = pPPortion->GetLines()[ nLine ];
+ aPaM.GetIndex() = pLine->GetEnd();
+
+ if ( pLine->GetEnd() > pLine->GetStart() ) // Leerzeile
+ {
+ xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((sal_uInt16)(aPaM.GetIndex()-1) );
+ if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().Len() ) )
+ {
+ // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn,
+ // davor zu stehen, da der Anwender hinter das Wort will.
+ // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End!
+ aPaM.GetIndex()--;
+ }
+ }
+ return aPaM;
+}
+
+TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+ aPaM.GetIndex() = 0;
+ return aPaM;
+}
+
+TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM )
+{
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( rPaM.GetPara() );
+ TextPaM aPaM( rPaM );
+ aPaM.GetIndex() = pNode->GetText().Len();
+ return aPaM;
+}
+
+TextPaM TextView::CursorStartOfDoc()
+{
+ TextPaM aPaM( 0, 0 );
+ return aPaM;
+}
+
+TextPaM TextView::CursorEndOfDoc()
+{
+ sal_uLong nNode = mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1;
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( nNode );
+ TextPaM aPaM( nNode, pNode->GetText().Len() );
+ return aPaM;
+}
+
+TextPaM TextView::PageUp( const TextPaM& rPaM )
+{
+ Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM );
+ Point aTopLeft = aRec.TopLeft();
+ aTopLeft.Y() -= mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10;
+ aTopLeft.X() += 1;
+ if ( aTopLeft.Y() < 0 )
+ aTopLeft.Y() = 0;
+
+ TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft );
+ return aPaM;
+}
+
+TextPaM TextView::PageDown( const TextPaM& rPaM )
+{
+ Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM );
+ Point aBottomRight = aRec.BottomRight();
+ aBottomRight.Y() += mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10;
+ aBottomRight.X() += 1;
+ long nHeight = mpImpl->mpTextEngine->GetTextHeight();
+ if ( aBottomRight.Y() > nHeight )
+ aBottomRight.Y() = nHeight-1;
+
+ TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight );
+ return aPaM;
+}
+
+void TextView::ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bSpecial )
+{
+ if ( mpImpl->mpTextEngine->IsFormatting() )
+ return;
+ if ( mpImpl->mpTextEngine->GetUpdateMode() == sal_False )
+ return;
+ if ( mpImpl->mpTextEngine->IsInUndo() )
+ return;
+
+ mpImpl->mpTextEngine->CheckIdleFormatter();
+ if ( !mpImpl->mpTextEngine->IsFormatted() )
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+
+
+ TextPaM aPaM( mpImpl->maSelection.GetEnd() );
+ Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial );
+
+ // Remember that we placed the cursor behind the last character of a line
+ mpImpl->mbCursorAtEndOfLine = false;
+ if( bSpecial )
+ {
+ TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ mpImpl->mbCursorAtEndOfLine =
+ pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
+ }
+
+ if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() )
+ {
+ TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) )
+ {
+ // If we are behind a portion, and the next portion has other direction, we must change position...
+ aEditCursor.Left() = aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aPaM, sal_False, sal_True ).Left();
+
+ TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+
+ sal_uInt16 nTextPortionStart = 0;
+ sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, sal_True );
+ TETextPortion* pTextPortion = pParaPortion->GetTextPortions()[ nTextPortion ];
+ if ( pTextPortion->GetKind() == PORTIONKIND_TAB )
+ {
+ if ( mpImpl->mpTextEngine->IsRightToLeft() )
+ {
+
+ }
+ aEditCursor.Right() += pTextPortion->GetWidth();
+ }
+ else
+ {
+ TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL );
+ aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, sal_True ).Left();
+ }
+ }
+ }
+
+ Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel();
+ if ( aEditCursor.GetHeight() > aOutSz.Height() )
+ aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1;
+
+ aEditCursor.Left() -= 1;
+
+ if ( bGotoCursor
+ // #i81283# protext maStartDocPos against initialization problems
+ && aOutSz.Width() && aOutSz.Height()
+ )
+ {
+ long nVisStartY = mpImpl->maStartDocPos.Y();
+ long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height();
+ long nVisStartX = mpImpl->maStartDocPos.X();
+ long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width();
+ long nMoreX = aOutSz.Width() / 4;
+
+ Point aNewStartPos( mpImpl->maStartDocPos );
+
+ if ( aEditCursor.Bottom() > nVisEndY )
+ {
+ aNewStartPos.Y() += ( aEditCursor.Bottom() - nVisEndY );
+ }
+ else if ( aEditCursor.Top() < nVisStartY )
+ {
+ aNewStartPos.Y() -= ( nVisStartY - aEditCursor.Top() );
+ }
+
+ if ( aEditCursor.Right() >= nVisEndX )
+ {
+ aNewStartPos.X() += ( aEditCursor.Right() - nVisEndX );
+
+ // Darfs ein bischen mehr sein?
+ aNewStartPos.X() += nMoreX;
+ }
+ else if ( aEditCursor.Left() <= nVisStartX )
+ {
+ aNewStartPos.X() -= ( nVisStartX - aEditCursor.Left() );
+
+ // Darfs ein bischen mehr sein?
+ aNewStartPos.X() -= nMoreX;
+ }
+
+ // X kann durch das 'bischen mehr' falsch sein:
+// sal_uLong nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth();
+// if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) )
+// nMaxTextWidth = 0x7FFFFFFF;
+// long nMaxX = (long)nMaxTextWidth - aOutSz.Width();
+ long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width();
+ if ( nMaxX < 0 )
+ nMaxX = 0;
+
+ if ( aNewStartPos.X() < 0 )
+ aNewStartPos.X() = 0;
+ else if ( aNewStartPos.X() > nMaxX )
+ aNewStartPos.X() = nMaxX;
+
+ // Y sollte nicht weiter unten als noetig liegen:
+ long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height();
+ if ( nYMax < 0 )
+ nYMax = 0;
+ if ( aNewStartPos.Y() > nYMax )
+ aNewStartPos.Y() = nYMax;
+
+ if ( aNewStartPos != mpImpl->maStartDocPos )
+ Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) );
+ }
+
+ if ( aEditCursor.Right() < aEditCursor.Left() )
+ {
+ long n = aEditCursor.Left();
+ aEditCursor.Left() = aEditCursor.Right();
+ aEditCursor.Right() = n;
+ }
+
+ Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) );
+ mpImpl->mpCursor->SetPos( aPoint );
+ mpImpl->mpCursor->SetSize( aEditCursor.GetSize() );
+ if ( bForceVisCursor && mpImpl->mbCursorEnabled )
+ mpImpl->mpCursor->Show();
+}
+
+sal_Bool TextView::SetCursorAtPoint( const Point& rPosPixel )
+{
+ mpImpl->mpTextEngine->CheckIdleFormatter();
+
+ Point aDocPos = GetDocPos( rPosPixel );
+
+ TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos );
+
+ // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion
+ TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM );
+ TextSelection aNewSel( mpImpl->maSelection );
+ aNewSel.GetEnd() = aPaM;
+
+ if ( !mpImpl->mpSelEngine->HasAnchor() )
+ {
+ if ( mpImpl->maSelection.GetStart() != aPaM )
+ mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() );
+ aNewSel.GetStart() = aPaM;
+ ImpSetSelection( aNewSel );
+ }
+ else
+ {
+ ImpSetSelection( aNewSel );
+ ShowSelection( aTmpNewSel );
+ }
+
+ sal_Bool bForceCursor = mpImpl->mpDDInfo ? sal_False : sal_True; // && !mbInSelection
+ ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, sal_False );
+ return sal_True;
+}
+
+sal_Bool TextView::IsSelectionAtPoint( const Point& rPosPixel )
+{
+// if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection )
+// return sal_False;
+
+ Point aDocPos = GetDocPos( rPosPixel );
+ TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos, sal_False );
+ // Bei Hyperlinks D&D auch ohne Selektion starten.
+ // BeginDrag wird aber nur gerufen, wenn IsSelectionAtPoint()
+ // Problem: IsSelectionAtPoint wird bei Command() nicht gerufen,
+ // wenn vorher im MBDown schon sal_False returnt wurde.
+ return ( IsInSelection( aPaM ) ||
+ ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) );
+}
+
+sal_Bool TextView::IsInSelection( const TextPaM& rPaM )
+{
+ TextSelection aSel = mpImpl->maSelection;
+ aSel.Justify();
+
+ sal_uLong nStartNode = aSel.GetStart().GetPara();
+ sal_uLong nEndNode = aSel.GetEnd().GetPara();
+ sal_uLong nCurNode = rPaM.GetPara();
+
+ if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) )
+ return sal_True;
+
+ if ( nStartNode == nEndNode )
+ {
+ if ( nCurNode == nStartNode )
+ if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
+ return sal_True;
+ }
+ else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) )
+ return sal_True;
+ else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+void TextView::ImpHideDDCursor()
+{
+ if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor )
+ {
+ mpImpl->mpDDInfo->maCursor.Hide();
+ mpImpl->mpDDInfo->mbVisCursor = sal_False;
+ }
+}
+
+void TextView::ImpShowDDCursor()
+{
+ if ( !mpImpl->mpDDInfo->mbVisCursor )
+ {
+ Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, sal_True );
+ aCursor.Right()++;
+ aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) );
+
+ mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow );
+ mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() );
+ mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() );
+ mpImpl->mpDDInfo->maCursor.Show();
+ mpImpl->mpDDInfo->mbVisCursor = sal_True;
+ }
+}
+
+void TextView::SetPaintSelection( sal_Bool bPaint )
+{
+ if ( bPaint != mpImpl->mbPaintSelection )
+ {
+ mpImpl->mbPaintSelection = bPaint;
+ ShowSelection( mpImpl->maSelection );
+ }
+}
+
+sal_Bool TextView::Read( SvStream& rInput )
+{
+ sal_Bool bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection );
+ ShowCursor();
+ return bDone;
+}
+
+bool TextView::ImplTruncateNewText( rtl::OUString& rNewText ) const
+{
+ bool bTruncated = false;
+
+ if( rNewText.getLength() > 65534 ) // limit to String API
+ {
+ rNewText = rNewText.copy( 0, 65534 );
+ bTruncated = true;
+ }
+
+ sal_uLong nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen();
+ // 0 means unlimited, there is just the String API limit handled above
+ if( nMaxLen != 0 )
+ {
+ sal_uLong nCurLen = mpImpl->mpTextEngine->GetTextLen();
+
+ sal_uInt32 nNewLen = rNewText.getLength();
+ if ( nCurLen + nNewLen > nMaxLen )
+ {
+ // see how much text will be replaced
+ sal_uLong nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection );
+ if ( nCurLen + nNewLen - nSelLen > nMaxLen )
+ {
+ sal_uInt32 nTruncatedLen = static_cast<sal_uInt32>(nMaxLen - (nCurLen - nSelLen));
+ rNewText = rNewText.copy( 0, nTruncatedLen );
+ bTruncated = true;
+ }
+ }
+ }
+ return bTruncated;
+}
+
+sal_Bool TextView::ImplCheckTextLen( const String& rNewText )
+{
+ sal_Bool bOK = sal_True;
+ if ( mpImpl->mpTextEngine->GetMaxTextLen() )
+ {
+ sal_uLong n = mpImpl->mpTextEngine->GetTextLen();
+ n += rNewText.Len();
+ if ( n > mpImpl->mpTextEngine->GetMaxTextLen() )
+ {
+ // nur dann noch ermitteln, wie viel Text geloescht wird
+ n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection );
+ if ( n > mpImpl->mpTextEngine->GetMaxTextLen() )
+ bOK = sal_False;
+ }
+ }
+ return bOK;
+}
+
+void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpImpl->mbClickedInSelection )
+ {
+ SolarMutexGuard aVclGuard;
+
+ DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" );
+
+ delete mpImpl->mpDDInfo;
+ mpImpl->mpDDInfo = new TextDDInfo;
+ mpImpl->mpDDInfo->mbStarterOfDD = sal_True;
+
+ TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
+
+ if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML
+ mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True );
+
+
+ /*
+ // D&D eines Hyperlinks.
+ // Besser waere es im MBDown sich den MBDownPaM zu merken,
+ // ist dann aber inkompatibel => spaeter mal umstellen.
+ TextPaM aPaM( mpImpl->mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) );
+ const TextCharAttrib* pAttr = mpImpl->mpTextEngine->FindCharAttrib( aPaM, TEXTATTR_HYPERLINK );
+ if ( pAttr )
+ {
+ aSel = aPaM;
+ aSel.GetStart().GetIndex() = pAttr->GetStart();
+ aSel.GetEnd().GetIndex() = pAttr->GetEnd();
+
+ const TextAttribHyperLink& rLink = (const TextAttribHyperLink&)pAttr->GetAttr();
+ String aText( rLink.GetDescription() );
+ if ( !aText.Len() )
+ aText = mpImpl->mpTextEngine->GetText( aSel );
+ INetBookmark aBookmark( rLink.GetURL(), aText );
+ aBookmark.CopyDragServer();
+ }
+ */
+
+ mpImpl->mpCursor->Hide();
+
+ sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
+ if ( !IsReadOnly() )
+ nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
+ rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener );
+ }
+}
+
+void TextView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& ) throw (::com::sun::star::uno::RuntimeException)
+{
+ ImpHideDDCursor();
+ delete mpImpl->mpDDInfo;
+ mpImpl->mpDDInfo = NULL;
+}
+
+void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ SolarMutexGuard aVclGuard;
+
+ sal_Bool bChanges = sal_False;
+ if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo )
+ {
+ ImpHideDDCursor();
+
+ // Daten fuer das loeschen nach einem DROP_MOVE:
+ TextSelection aPrevSel( mpImpl->maSelection );
+ aPrevSel.Justify();
+ sal_uLong nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount();
+ sal_uInt16 nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() );
+
+ sal_Bool bStarterOfDD = sal_False;
+ for ( sal_uInt16 nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; )
+ bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : sal_False;
+
+ HideSelection();
+ ImpSetSelection( mpImpl->mpDDInfo->maDropPos );
+
+ mpImpl->mpTextEngine->UndoActionStart();
+
+ String aText;
+ uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
+ if ( xDataObj.is() )
+ {
+ datatransfer::DataFlavor aFlavor;
+ SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
+ if ( xDataObj->isDataFlavorSupported( aFlavor ) )
+ {
+ uno::Any aData = xDataObj->getTransferData( aFlavor );
+ ::rtl::OUString aOUString;
+ aData >>= aOUString;
+ aText = convertLineEnd(aOUString, LINEEND_LF);
+ }
+ }
+
+ if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) )
+ aText.Erase( aText.Len()-1 );
+
+ TextPaM aTempStart = mpImpl->maSelection.GetStart();
+ if ( ImplCheckTextLen( aText ) )
+ ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) );
+ if(mpImpl->mbSupportProtectAttribute)
+ {
+ mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(),
+ aTempStart.GetPara(),
+ aTempStart.GetIndex(),
+ mpImpl->maSelection.GetEnd().GetIndex(), sal_False );
+ }
+
+ if ( aPrevSel.HasRange() &&
+ !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element
+ (( rDTDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) )
+ {
+ // ggf. Selection anpasssen:
+ if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) ||
+ ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
+ && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) )
+ {
+ sal_uLong nNewParasBeforeSelection =
+ mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount;
+
+ aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection;
+ aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection;
+
+ if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
+ {
+ sal_uInt16 nNewChars =
+ mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen;
+
+ aPrevSel.GetStart().GetIndex() =
+ aPrevSel.GetStart().GetIndex() + nNewChars;
+ if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() )
+ aPrevSel.GetEnd().GetIndex() =
+ aPrevSel.GetEnd().GetIndex() + nNewChars;
+ }
+ }
+ else
+ {
+ // aktuelle Selektion anpassen
+ TextPaM aPaM = mpImpl->maSelection.GetStart();
+ aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() );
+ if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() )
+ {
+ aPaM.GetIndex() =
+ aPaM.GetIndex() - aPrevSel.GetEnd().GetIndex();
+ if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() )
+ aPaM.GetIndex() =
+ aPaM.GetIndex() + aPrevSel.GetStart().GetIndex();
+ }
+ ImpSetSelection( aPaM );
+
+ }
+ mpImpl->mpTextEngine->ImpDeleteText( aPrevSel );
+ }
+
+ mpImpl->mpTextEngine->UndoActionEnd();
+
+ delete mpImpl->mpDDInfo;
+ mpImpl->mpDDInfo = 0;
+
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ }
+ rDTDE.Context->dropComplete( bChanges );
+}
+
+void TextView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException)
+{
+}
+
+void TextView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
+{
+ SolarMutexGuard aVclGuard;
+ ImpHideDDCursor();
+}
+
+void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ SolarMutexGuard aVclGuard;
+
+ if ( !mpImpl->mpDDInfo )
+ mpImpl->mpDDInfo = new TextDDInfo;
+
+ TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos;
+ Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
+ Point aDocPos = GetDocPos( aMousePos );
+ mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos );
+
+ sal_Bool bProtected = sal_False;
+ if(mpImpl->mbSupportProtectAttribute)
+ {
+ const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib(
+ mpImpl->mpDDInfo->maDropPos,
+ TEXTATTR_PROTECTED );
+ bProtected = pStartAttr != 0 &&
+ pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() &&
+ pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex();
+ }
+ // Don't drop in selection or in read only engine
+ if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected)
+ {
+ ImpHideDDCursor();
+ rDTDE.Context->rejectDrag();
+ }
+ else
+ {
+ // Alten Cursor wegzeichnen...
+ if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) )
+ {
+ ImpHideDDCursor();
+ ImpShowDDCursor();
+ }
+ rDTDE.Context->acceptDrag( rDTDE.DropAction );
+ }
+}
+
+Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const
+{
+ Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() );
+ if ( mpImpl->mpTextEngine->IsRightToLeft() )
+ {
+ Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
+ aStartPos.X() = rStartDocPos.X() + aSz.Width() - 1; // -1: Start is 0
+ }
+ return aStartPos;
+}
+
+Point TextView::GetDocPos( const Point& rWindowPos ) const
+{
+ // Fensterposition => Dokumentposition
+
+ Point aPoint;
+
+ aPoint.Y() = rWindowPos.Y() + mpImpl->maStartDocPos.Y();
+
+ if ( !mpImpl->mpTextEngine->IsRightToLeft() )
+ {
+ aPoint.X() = rWindowPos.X() + mpImpl->maStartDocPos.X();
+ }
+ else
+ {
+ Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
+ aPoint.X() = ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X();
+ }
+
+ return aPoint;
+}
+
+Point TextView::GetWindowPos( const Point& rDocPos ) const
+{
+ // Dokumentposition => Fensterposition
+
+ Point aPoint;
+
+ aPoint.Y() = rDocPos.Y() - mpImpl->maStartDocPos.Y();
+
+ if ( !mpImpl->mpTextEngine->IsRightToLeft() )
+ {
+ aPoint.X() = rDocPos.X() - mpImpl->maStartDocPos.X();
+ }
+ else
+ {
+ Size aSz = mpImpl->mpWindow->GetOutputSizePixel();
+ aPoint.X() = ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() );
+ }
+
+ return aPoint;
+}
+
+sal_Int32 TextView::GetLineNumberOfCursorInSelection() const
+{
+ // PROGRESS
+ sal_Int32 nLineNo = -1;
+ if( mpImpl->mbCursorEnabled )
+ {
+ TextPaM aPaM = GetSelection().GetEnd();
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False );
+ if( mpImpl->mbCursorAtEndOfLine )
+ --nLineNo;
+ }
+ return nLineNo;
+}
+
+
+// -------------------------------------------------------------------------
+// (+) class TextSelFunctionSet
+// -------------------------------------------------------------------------
+TextSelFunctionSet::TextSelFunctionSet( TextView* pView )
+{
+ mpView = pView;
+}
+
+void TextSelFunctionSet::BeginDrag()
+{
+}
+
+void TextSelFunctionSet::CreateAnchor()
+{
+// TextSelection aSel( mpView->GetSelection() );
+// aSel.GetStart() = aSel.GetEnd();
+// mpView->SetSelection( aSel );
+
+ // Es darf kein ShowCursor folgen:
+ mpView->HideSelection();
+ mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() );
+}
+
+sal_Bool TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, sal_Bool )
+{
+ return mpView->SetCursorAtPoint( rPointPixel );
+}
+
+sal_Bool TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
+{
+ return mpView->IsSelectionAtPoint( rPointPixel );
+}
+
+void TextSelFunctionSet::DeselectAll()
+{
+ CreateAnchor();
+}
+
+void TextSelFunctionSet::DeselectAtPoint( const Point& )
+{
+ // Nur bei Mehrfachselektion
+}
+
+void TextSelFunctionSet::DestroyAnchor()
+{
+ // Nur bei Mehrfachselektion
+}
+TextEngine* TextView::GetTextEngine() const
+{ return mpImpl->mpTextEngine; }
+Window* TextView::GetWindow() const
+{ return mpImpl->mpWindow; }
+void TextView::EnableCursor( sal_Bool bEnable )
+{ mpImpl->mbCursorEnabled = bEnable; }
+sal_Bool TextView::IsCursorEnabled() const
+{ return mpImpl->mbCursorEnabled; }
+void TextView::SetStartDocPos( const Point& rPos )
+{ mpImpl->maStartDocPos = rPos; }
+const Point& TextView::GetStartDocPos() const
+{ return mpImpl->maStartDocPos; }
+void TextView::SetAutoIndentMode( sal_Bool bAutoIndent )
+{ mpImpl->mbAutoIndent = bAutoIndent; }
+sal_Bool TextView::IsReadOnly() const
+{ return mpImpl->mbReadOnly; }
+void TextView::SetAutoScroll( sal_Bool bAutoScroll )
+{ mpImpl->mbAutoScroll = bAutoScroll; }
+sal_Bool TextView::IsAutoScroll() const
+{ return mpImpl->mbAutoScroll; }
+sal_Bool TextView::HasSelection() const
+{ return mpImpl->maSelection.HasRange(); }
+sal_Bool TextView::IsInsertMode() const
+{ return mpImpl->mbInsertMode; }
+void TextView::SupportProtectAttribute(sal_Bool bSupport)
+{ mpImpl->mbSupportProtectAttribute = bSupport;}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */