summaryrefslogtreecommitdiff
path: root/svtools/source/edit/textview.cxx
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2000-09-18 16:07:07 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2000-09-18 16:07:07 +0000
commit8ab086b6cc054501bfbf7ef6fa509c393691e860 (patch)
tree324d51845d7f1a2f4e02a14db22fb5947137c822 /svtools/source/edit/textview.cxx
parent411e68cc54ae97eebd79ae3a9cb2971b74cb2a9e (diff)
initial import
Diffstat (limited to 'svtools/source/edit/textview.cxx')
-rw-r--r--svtools/source/edit/textview.cxx1760
1 files changed, 1760 insertions, 0 deletions
diff --git a/svtools/source/edit/textview.cxx b/svtools/source/edit/textview.cxx
new file mode 100644
index 000000000000..df85abfbf485
--- /dev/null
+++ b/svtools/source/edit/textview.cxx
@@ -0,0 +1,1760 @@
+/*************************************************************************
+ *
+ * $RCSfile: textview.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:58:58 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#pragma hdrstop
+
+#include <textview.hxx>
+#include <texteng.hxx>
+#include <textdoc.hxx>
+#include <textdata.hxx>
+#include <textdat2.hxx>
+
+#include <undo.hxx>
+
+#ifndef _SV_CURSOR_HXX //autogen
+#include <vcl/cursor.hxx>
+#endif
+
+#ifndef _SV_WINDOW_HXX //autogen
+#include <vcl/window.hxx>
+#endif
+
+#ifndef _SV_SVAPP_HXX //autogen
+#include <vcl/svapp.hxx>
+#endif
+
+#ifndef _SV_CLIP_HXX //autogen
+#include <vcl/clip.hxx>
+#endif
+
+#ifndef _SV_DRAG_HXX //autogen
+#include <vcl/drag.hxx>
+#endif
+
+#ifndef _SV_SOUND_HXX //autogen
+#include <vcl/sound.hxx>
+#endif
+
+#ifndef _STREAM_HXX //autogen
+#include <tools/stream.hxx>
+#endif
+
+#ifndef _NEW_HXX
+#include <tools/new.hxx>
+#endif
+
+#include <sot/formats.hxx>
+
+#ifndef _URLBMK_HXX
+#include <urlbmk.hxx>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_
+#include <com/sun/star/text/XBreakIterator.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_
+#include <com/sun/star/text/CharacterIteratorMode.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
+#include <com/sun/star/text/WordType.hpp>
+#endif
+
+using namespace ::com::sun::star;
+
+
+ // -------------------------------------------------------------------------
+// (+) class TextView
+// -------------------------------------------------------------------------
+TextView::TextView( TextEngine* pEng, Window* pWindow )
+{
+ mpWindow = pWindow;
+ mpTextEngine = pEng;
+ mpVirtDev = NULL;
+
+ mbPaintSelection = TRUE;
+ mbAutoScroll = TRUE;
+ mbInsertMode = TRUE;
+ mbReadOnly = FALSE;
+ mbHighlightSelection = FALSE;
+ mbAutoIndent = FALSE;
+ mbCursorEnabled = TRUE;
+// mbInSelection = FALSE;
+
+ mnTravelXPos = TRAVEL_X_DONTKNOW;
+
+ mpSelFuncSet = new TextSelFunctionSet( this );
+ mpSelEngine = new SelectionEngine( mpWindow, mpSelFuncSet );
+ mpSelEngine->SetSelectionMode( RANGE_SELECTION );
+ mpSelEngine->EnableDrag( TRUE );
+
+ mpCursor = new Cursor;
+ mpCursor->Show();
+ pWindow->SetCursor( mpCursor );
+
+ if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT )
+ mbHighlightSelection = TRUE;
+
+ pWindow->SetLineColor();
+
+ mpDDInfo = 0;
+}
+
+TextView::~TextView()
+{
+ delete mpSelEngine;
+ delete mpSelFuncSet;
+ delete mpVirtDev;
+
+ if ( mpWindow->GetCursor() == mpCursor )
+ mpWindow->SetCursor( 0 );
+ delete mpCursor;
+ delete mpDDInfo;
+}
+
+void TextView::Invalidate()
+{
+ mpWindow->Invalidate();
+}
+
+void TextView::SetSelection( const TextSelection& rTextSel, BOOL bGotoCursor )
+{
+ // Falls jemand gerade ein leeres Attribut hinterlassen hat,
+ // und dann der Outliner die Selektion manipulitert:
+ if ( !maSelection.HasRange() )
+ mpTextEngine->CursorMoved( maSelection.GetStart().GetPara() );
+
+ // Wenn nach einem KeyInput die Selection manipuliert wird:
+ mpTextEngine->CheckIdleFormatter();
+
+ HideSelection();
+ maSelection = rTextSel;
+ mpTextEngine->ValidateSelection( maSelection );
+ ShowSelection();
+ ShowCursor( bGotoCursor );
+}
+
+void TextView::SetSelection( const TextSelection& rTextSel )
+{
+ SetSelection( rTextSel, mbAutoScroll );
+}
+
+const TextSelection& TextView::GetSelection() const
+{
+ return maSelection;
+}
+
+void TextView::DeleteSelected()
+{
+// HideSelection();
+
+ mpTextEngine->UndoActionStart( TEXTUNDO_DELETE );
+ TextPaM aPaM = mpTextEngine->ImpDeleteText( maSelection );
+ mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE );
+
+ maSelection = aPaM;
+ mpTextEngine->FormatAndUpdate( this );
+ ShowCursor();
+}
+
+void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection )
+{
+ if ( !mbPaintSelection )
+ pSelection = NULL;
+ else
+ {
+ // Richtige Hintergrundfarbe einstellen.
+ // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat.
+ Font aFont = mpTextEngine->GetFont();
+ Color aColor = pOut->GetBackground().GetColor();
+ aColor.SetTransparency( 0 );
+ if ( aColor != aFont.GetFillColor() )
+ {
+ aFont.SetTransparent( FALSE );
+ aFont.SetFillColor( aColor );
+ mpTextEngine->maFont = aFont;
+ }
+ }
+
+ mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection );
+}
+
+void TextView::Paint( const Rectangle& rRect )
+{
+ ImpPaint( rRect, FALSE );
+}
+
+void TextView::ImpPaint( const Rectangle& rRect, BOOL bUseVirtDev )
+{
+ if ( !mpTextEngine->GetUpdateMode() || mpTextEngine->IsInUndo() )
+ return;
+
+ if ( bUseVirtDev )
+ {
+ VirtualDevice* pVDev = GetVirtualDevice();
+
+ const Color& rBackgroundColor = mpWindow->GetBackground().GetColor();
+ if ( pVDev->GetFillColor() != rBackgroundColor )
+ pVDev->SetFillColor( rBackgroundColor );
+ if ( pVDev->GetBackground().GetColor() != rBackgroundColor )
+ pVDev->SetBackground( rBackgroundColor );
+
+ BOOL bVDevValid = 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, FALSE /* ohne VDev */ );
+ return;
+ }
+
+ Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() );
+ Point aStartPos = GetDocPos( rRect.TopLeft() );
+ aStartPos.X() *= (-1);
+ aStartPos.Y() *= (-1);
+
+ TextSelection *pTmpPtr = mbHighlightSelection ? NULL : &maSelection;
+ ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pTmpPtr );
+
+ mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(),
+ Point(0,0), rRect.GetSize(), *pVDev );
+
+// ShowSelection();
+ if ( mbHighlightSelection )
+ ImpHighlight( maSelection );
+ }
+ else
+ {
+ Point aStartPos( -maStartDocPos.X(), -maStartDocPos.Y() );
+
+ TextSelection *pTmpPtr = mbHighlightSelection ? NULL : &maSelection;
+ ImpPaint( mpWindow, aStartPos, &rRect, NULL, pTmpPtr );
+
+// ShowSelection();
+ if ( mbHighlightSelection )
+ ImpHighlight( maSelection );
+ }
+}
+
+void TextView::ImpHighlight( const TextSelection& rSel )
+{
+ TextSelection aSel( rSel );
+ aSel.Justify();
+ if ( aSel.HasRange() && !mpTextEngine->IsInUndo() && mpTextEngine->GetUpdateMode() )
+ {
+ BOOL bInvertSelection = FALSE;
+#ifdef MAC
+ bInvertSelection = ( mpWindow->GetBackground().GetColor() != COL_WHITE );
+#endif
+ mpCursor->Hide();
+
+ DBG_ASSERT( !mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" );
+
+ Rectangle aVisArea( maStartDocPos, mpWindow->GetOutputSizePixel() );
+ long nY = 0;
+ ULONG nStartPara = aSel.GetStart().GetPara();
+ ULONG nEndPara = aSel.GetEnd().GetPara();
+ for ( ULONG nPara = 0; nPara <= nEndPara; nPara++ )
+ {
+ long nParaHeight = (long)mpTextEngine->CalcParaHeight( nPara );
+ if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) )
+ {
+ TEParaPortion* pTEParaPortion = mpTextEngine->mpTEParaPortions->GetObject( nPara );
+ USHORT nStartLine = 0;
+ USHORT nEndLine = pTEParaPortion->GetLines().Count() -1;
+ if ( nPara == nStartPara )
+ nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), FALSE );
+ if ( nPara == nEndPara )
+ nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), TRUE );
+
+ // ueber die Zeilen iterieren....
+ for ( USHORT nLine = nStartLine; nLine <= nEndLine; nLine++ )
+ {
+ TextLine* pLine = pTEParaPortion->GetLines().GetObject( nLine );
+ USHORT nStartIndex = pLine->GetStart();
+ USHORT 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( mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), FALSE ) );
+ aTmpRec.Top() += nY;
+ aTmpRec.Bottom() += nY;
+ Point aTopLeft( aTmpRec.TopLeft() );
+
+ aTmpRec = mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), 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 );
+ /*! (pb) NOOLDSV
+ if ( bInvertSelection )
+ mpWindow->InvertRect( aRect );
+ else
+ mpWindow->HighlightRect( aRect );
+ */
+ mpWindow->Invert( aRect );
+ }
+ }
+ }
+ nY += nParaHeight;
+
+ if ( nY >= aVisArea.Bottom() )
+ break;
+ }
+ }
+}
+
+
+void TextView::ShowSelection()
+{
+ if ( maSelection.HasRange() )
+ {
+ if ( mbHighlightSelection )
+ ImpHighlight( maSelection );
+ else
+ {
+ // Den Bereich neu zeichnen...
+ Rectangle aOutArea( Point( 0, 0 ), mpWindow->GetOutputSizePixel() );
+ Point aStartPos( -maStartDocPos.X(), -maStartDocPos.Y() );
+ TextSelection aRange( maSelection );
+ aRange.Justify();
+ BOOL bVisCursor = mpCursor->IsVisible();
+ mpCursor->Hide();
+ ImpPaint( mpWindow, aStartPos, &aOutArea, &aRange, &maSelection );
+ if ( bVisCursor )
+ mpCursor->Show();
+ }
+ }
+}
+
+void TextView::HideSelection()
+{
+ if ( maSelection.HasRange() )
+ {
+ if ( mbHighlightSelection )
+ ImpHighlight( maSelection );
+ else
+ {
+ // Den Bereich neu zeichnen...
+ Rectangle aOutArea( Point( 0, 0 ), mpWindow->GetOutputSizePixel() );
+ Point aStartPos( -maStartDocPos.X(), -maStartDocPos.Y() );
+ TextSelection aRange( maSelection );
+ aRange.Justify();
+ BOOL bVisCursor = mpCursor->IsVisible();
+ mpCursor->Hide();
+ ImpPaint( mpWindow, aStartPos, &aOutArea, &aRange, NULL );
+ if ( bVisCursor )
+ mpCursor->Show();
+ }
+ }
+}
+
+void TextView::ShowSelection( const TextSelection& rRange )
+{
+ if ( rRange.HasRange() )
+ {
+ if ( mbHighlightSelection )
+ ImpHighlight( rRange );
+ else
+ {
+ // Den Bereich neu zeichnen...
+ Rectangle aOutArea( Point( 0, 0 ), mpWindow->GetOutputSizePixel() );
+ Point aStartPos( -maStartDocPos.X(), -maStartDocPos.Y() );
+ TextSelection aRange( rRange );
+ aRange.Justify();
+ BOOL bVisCursor = mpCursor->IsVisible();
+ mpCursor->Hide();
+ ImpPaint( mpWindow, aStartPos, &aOutArea, &aRange, &maSelection );
+ if ( bVisCursor )
+ mpCursor->Show();
+ }
+ }
+}
+
+VirtualDevice* TextView::GetVirtualDevice()
+{
+ if ( !mpVirtDev )
+ {
+ mpVirtDev = new VirtualDevice;
+ mpVirtDev->SetLineColor();
+ }
+ return mpVirtDev;
+}
+
+void TextView::EraseVirtualDevice()
+{
+ delete mpVirtDev;
+ mpVirtDev = 0;
+}
+
+BOOL TextView::KeyInput( const KeyEvent& rKeyEvent )
+{
+ BOOL bDone = TRUE;
+ BOOL bModified = FALSE;
+ BOOL bMoved = FALSE;
+ BOOL bEndKey = FALSE; // spezielle CursorPosition
+ BOOL bAllowIdle = 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.
+ BOOL bWasModified = mpTextEngine->IsModified();
+ mpTextEngine->SetModified( FALSE );
+
+ TextSelection aCurSel( maSelection );
+ TextSelection aOldSel( aCurSel );
+
+ USHORT nCode = rKeyEvent.GetKeyCode().GetCode();
+ KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
+ if ( eFunc != KEYFUNC_DONTKNOW )
+ {
+ switch ( eFunc )
+ {
+ case KEYFUNC_CUT:
+ {
+ if ( !mbReadOnly )
+ Cut();
+ }
+ break;
+ case KEYFUNC_COPY:
+ {
+ Copy();
+ }
+ break;
+ case KEYFUNC_PASTE:
+ {
+ if ( !mbReadOnly )
+ Paste();
+ }
+ break;
+ case KEYFUNC_UNDO:
+ {
+ if ( !mbReadOnly )
+ Undo();
+ }
+ break;
+ case KEYFUNC_REDO:
+ {
+ if ( !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:
+ {
+ if ( !rKeyEvent.GetKeyCode().IsMod2() )
+ {
+ aCurSel = ImpMoveCursor( rKeyEvent );
+ bMoved = TRUE;
+ if ( nCode == KEY_END )
+ bEndKey = TRUE;
+ }
+ }
+ break;
+ case KEY_BACKSPACE:
+ case KEY_DELETE:
+ {
+ if ( !mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() )
+ {
+ BYTE nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT;
+ BYTE nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE;
+ if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() )
+ nMode = DELMODE_RESTOFCONTENT;
+
+ mpTextEngine->UndoActionStart( TEXTUNDO_DELETE );
+ aCurSel = ImpDelete( nDel, nMode );
+ mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE );
+ bModified = TRUE;
+ bAllowIdle = FALSE;
+ }
+ else
+ bDone = FALSE;
+ }
+ break;
+ case KEY_TAB:
+ {
+ if ( !mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() &&
+ !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() &&
+ ImplCheckTextLen( 'x' ) )
+ {
+ aCurSel = mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() );
+ bModified = TRUE;
+ }
+ else
+ bDone = FALSE;
+ }
+ break;
+ case KEY_RETURN:
+ {
+ // Shift-RETURN darf nicht geschluckt werden, weil dann keine
+ // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich.
+ if ( !mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() &&
+ !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( 'x' ) )
+ {
+ mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
+ aCurSel = mpTextEngine->ImpInsertParaBreak( aCurSel );
+ if ( mbAutoIndent )
+ {
+ TextNode* pPrev = mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 );
+ USHORT n = 0;
+ while ( ( n < pPrev->GetText().Len() ) && (
+ ( pPrev->GetText().GetChar( n ) == ' ' ) ||
+ ( pPrev->GetText().GetChar( n ) == '\t' ) ) )
+ {
+ n++;
+ }
+ if ( n )
+ aCurSel = mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) );
+ }
+ mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
+ bModified = TRUE;
+ }
+ else
+ bDone = FALSE;
+ }
+ break;
+ case KEY_INSERT:
+ {
+ if ( !mbReadOnly )
+ SetInsertMode( !IsInsertMode() );
+ }
+ break;
+ default:
+ {
+ if ( TextEngine::IsSimpleCharInput( rKeyEvent ) )
+ {
+ xub_Unicode nCharCode = rKeyEvent.GetCharCode();
+ if ( !mbReadOnly && ImplCheckTextLen( nCharCode ) ) // sonst trotzdem das Zeichen schlucken...
+ {
+ aCurSel = mpTextEngine->ImpInsertText( aCurSel, nCharCode, !IsInsertMode() );
+ bModified = TRUE;
+ }
+ }
+ else
+ bDone = FALSE;
+ }
+ }
+ }
+
+ if ( aCurSel != aOldSel )
+ maSelection = aCurSel;
+
+ mpTextEngine->UpdateSelections();
+
+ if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) )
+ mnTravelXPos = TRAVEL_X_DONTKNOW;
+
+ if ( bModified )
+ {
+ // Idle-Formatter nur, wenn AnyInput.
+ if ( bAllowIdle && Application::AnyInput( INPUT_KEYBOARD) )
+ mpTextEngine->IdleFormatAndUpdate( this );
+ else
+ mpTextEngine->FormatAndUpdate( this);
+ }
+ else if ( bMoved )
+ {
+ // Selection wird jetzt gezielt in ImpMoveCursor gemalt.
+ ImpShowCursor( mbAutoScroll, TRUE, bEndKey );
+ }
+
+ if ( mpTextEngine->IsModified() )
+ mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ else if ( bWasModified )
+ mpTextEngine->SetModified( TRUE );
+
+ return bDone;
+}
+
+void TextView::MouseButtonUp( const MouseEvent& rMouseEvent )
+{
+ mnTravelXPos = TRAVEL_X_DONTKNOW;
+ mpSelEngine->SelMouseButtonUp( rMouseEvent );
+}
+
+void TextView::MouseButtonDown( const MouseEvent& rMouseEvent )
+{
+ mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown
+ mnTravelXPos = TRAVEL_X_DONTKNOW;
+
+ mpTextEngine->SetActiveView( this );
+
+ mpSelEngine->SelMouseButtonDown( rMouseEvent );
+
+ // Sonderbehandlungen
+ if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) )
+ {
+ if ( rMouseEvent.IsMod2() )
+ {
+ HideSelection();
+ maSelection.GetStart() = maSelection.GetEnd();
+ SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // Wird von SelectionEngine bei MOD2 nicht gesetzt
+ }
+
+ if ( rMouseEvent.GetClicks() == 2 )
+ {
+ // Wort selektieren
+ if ( maSelection.GetEnd().GetIndex() < mpTextEngine->GetTextLen( maSelection.GetEnd().GetPara() ) )
+ {
+ HideSelection();
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( maSelection.GetEnd().GetPara() );
+ uno::Reference < text::XBreakIterator > xBI = mpTextEngine->GetBreakIterator();
+ text::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), maSelection.GetEnd().GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ maSelection.GetStart().GetIndex() = aBoundary.startPos;
+ maSelection.GetEnd().GetIndex() = aBoundary.endPos;
+ ShowSelection();
+ ShowCursor( TRUE, TRUE );
+ }
+ }
+ else if ( rMouseEvent.GetClicks() == 3 )
+ {
+ // Absatz selektieren
+ if ( maSelection.GetEnd().GetIndex() < mpTextEngine->GetTextLen( maSelection.GetEnd().GetPara() ) )
+ {
+ HideSelection();
+ maSelection.GetStart().GetIndex() = 0;
+ maSelection.GetEnd().GetIndex() = mpTextEngine->mpDoc->GetNodes().GetObject( maSelection.GetEnd().GetPara() )->GetText().Len();
+ ShowSelection();
+ ShowCursor( TRUE, TRUE );
+ }
+ }
+ }
+}
+
+
+void TextView::MouseMove( const MouseEvent& rMouseEvent )
+{
+ mnTravelXPos = TRAVEL_X_DONTKNOW;
+ mpSelEngine->SelMouseMove( rMouseEvent );
+}
+
+void TextView::Command( const CommandEvent& rCEvt )
+{
+ mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown
+ mpTextEngine->SetActiveView( this );
+ BOOL bCallSelectionEngineCommand = TRUE;
+ if ( ( rCEvt.GetCommand() == COMMAND_STARTDRAG ) )
+ {
+ }
+ if ( bCallSelectionEngineCommand )
+ mpSelEngine->Command( rCEvt );
+}
+
+void TextView::ShowCursor( BOOL bGotoCursor, BOOL bForceVisCursor )
+{
+ // Die Einstellung hat mehr Gewicht:
+ if ( !mbAutoScroll )
+ bGotoCursor = FALSE;
+ ImpShowCursor( bGotoCursor, bForceVisCursor, FALSE );
+}
+
+void TextView::HideCursor()
+{
+ mpCursor->Hide();
+}
+
+void TextView::Scroll( long ndX, long ndY )
+{
+ DBG_ASSERT( mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" );
+
+ if ( !ndX && !ndY )
+ return;
+
+ Point aNewStartPos( 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 = maStartDocPos.X() - aNewStartPos.X();
+ long nDiffY = maStartDocPos.Y() - aNewStartPos.Y();
+
+ if ( nDiffX || nDiffY )
+ {
+ BOOL bVisCursor = mpCursor->IsVisible();
+ mpCursor->Hide();
+ mpWindow->Update();
+ maStartDocPos = aNewStartPos;
+
+ mpWindow->Scroll( nDiffX, nDiffY );
+ mpWindow->Update();
+ mpCursor->SetPos( mpCursor->GetPos() + Point( nDiffX, nDiffY ) );
+ if ( bVisCursor && !mbReadOnly )
+ mpCursor->Show();
+ }
+}
+
+void TextView::Undo()
+{
+ mpTextEngine->SetActiveView( this );
+ mpTextEngine->GetUndoManager().Undo( 1 );
+}
+
+void TextView::Redo()
+{
+ mpTextEngine->SetActiveView( this );
+ mpTextEngine->GetUndoManager().Redo( 0 );
+}
+
+void TextView::Cut()
+{
+ mpTextEngine->UndoActionStart( TEXTUNDO_CUT );
+ Copy();
+ DeleteSelected();
+ mpTextEngine->UndoActionEnd( TEXTUNDO_CUT );
+}
+
+void TextView::Copy()
+{
+ Clipboard::Clear();
+ TextSelection aSel( maSelection );
+ aSel.Justify();
+ SvMemoryStream aMem;
+ mpTextEngine->Write( aMem, &aSel );
+ aMem << '\0';
+ Clipboard::CopyData( (const char*)aMem.GetData(), aMem.Tell(), FORMAT_STRING );
+ if ( mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) )
+ {
+ // Dann auch als HTML
+ aMem.SetStreamSize( 0 );
+ aMem.Seek( 0 );
+ mpTextEngine->Write( aMem, &aSel, TRUE );
+ aMem << '\0';
+ Clipboard::CopyData( (const char*)aMem.GetData(), aMem.Tell(), SOT_FORMATSTR_ID_HTML );
+ }
+}
+
+void TextView::Paste()
+{
+ BOOL bPaste = TRUE;
+ if ( mpTextEngine->GetMaxTextLen() )
+ {
+ // QuickCheck, kein String > 64K moeglich...
+ String aStr( Clipboard::PasteString() );
+ aStr.ConvertLineEnd( LINEEND_LF );
+ bPaste = ImplCheckTextLen( aStr );
+ }
+
+ if ( bPaste )
+ {
+ mpTextEngine->UndoActionStart( TEXTUNDO_PASTE );
+
+ ULONG nLen = Clipboard::GetDataLen( FORMAT_STRING );
+ void* pBuf = SvMemAlloc( nLen );
+ Clipboard::PasteData( pBuf, nLen, FORMAT_STRING );
+
+ // commented out while converting to Unicode
+ // long nStringLen = strlen( (const char*) pBuf ); // 0-terminiert, Datenmuell im Clipborad dahinter.
+
+ SvMemoryStream aMem( (char*)pBuf, nLen /*nStringLen*/, STREAM_READ );
+ aMem.ObjectOwnsMemory( TRUE );
+ mpTextEngine->Read( aMem, &maSelection );
+
+ mpTextEngine->UndoActionEnd( TEXTUNDO_PASTE );
+ }
+}
+
+String TextView::GetSelected()
+{
+ return mpTextEngine->GetText( maSelection, GetSystemLineEnd() );
+}
+
+void TextView::SetInsertMode( BOOL bInsert )
+{
+ if ( mbInsertMode != bInsert )
+ {
+ mbInsertMode = bInsert;
+ ShowCursor( mbAutoScroll, FALSE );
+ }
+}
+
+void TextView::SetReadOnly( BOOL bReadOnly )
+{
+ if ( mbReadOnly != bReadOnly )
+ {
+ mbReadOnly = bReadOnly;
+ if ( !mbReadOnly )
+ ShowCursor( mbAutoScroll, FALSE );
+ else
+ HideCursor();
+ }
+}
+
+TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent )
+{
+ // Eigentlich nur bei Up/Down noetig, aber was solls.
+ mpTextEngine->CheckIdleFormatter();
+
+ TextPaM aPaM( maSelection.GetEnd() );
+ TextPaM aOldEnd( aPaM );
+
+ BOOL bCtrl = rKeyEvent.GetKeyCode().IsMod1() ? TRUE : FALSE;
+
+ switch ( rKeyEvent.GetKeyCode().GetCode() )
+ {
+ 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 = CursorLeft( aPaM, bCtrl );
+ break;
+ case KEY_RIGHT: aPaM = CursorRight( aPaM, bCtrl );
+ break;
+ }
+
+ // Bewirkt evtl. ein CreateAnchor oder Deselection all
+ mpSelEngine->CursorPosChanging( rKeyEvent.GetKeyCode().IsShift(), rKeyEvent.GetKeyCode().IsMod1() );
+
+ if ( aOldEnd != aPaM )
+ {
+ mpTextEngine->CursorMoved( aOldEnd.GetPara() );
+
+
+ TextSelection aOldSelection( maSelection );
+ maSelection.GetEnd() = aPaM;
+ if ( rKeyEvent.GetKeyCode().IsShift() )
+ {
+ // Dann wird die Selektion erweitert...
+ ShowSelection( TextSelection( aOldEnd, aPaM ) );
+ }
+ else
+ {
+ maSelection.GetStart() = aPaM;
+ }
+ }
+
+ return maSelection;
+}
+
+void TextView::InsertText( const XubString& rStr, BOOL bSelect )
+{
+// HideSelection();
+
+ TextSelection aNewSel( maSelection );
+
+ mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
+ TextPaM aPaM = mpTextEngine->ImpInsertText( maSelection, rStr );
+ mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
+
+ if ( bSelect )
+ {
+ aNewSel.Justify();
+ aNewSel.GetEnd() = aPaM;
+ maSelection = aNewSel;
+ }
+ else
+ maSelection = aPaM;
+
+ mpTextEngine->FormatAndUpdate( this );
+}
+
+TextPaM TextView::CursorLeft( const TextPaM& rPaM, BOOL bWordMode )
+{
+ TextPaM aPaM( rPaM );
+
+ if ( aPaM.GetIndex() )
+ {
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ uno::Reference < text::XBreakIterator > xBI = mpTextEngine->GetBreakIterator();
+ if ( bWordMode )
+ {
+ text::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ if ( aBoundary.startPos == rPaM.GetIndex() )
+ aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES );
+ aPaM.GetIndex() = aBoundary.startPos;
+ }
+ else
+ {
+ sal_Int32 nCount = 1;
+ aPaM.GetIndex() = xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpTextEngine->GetLocale(), text::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
+ }
+ }
+ else if ( aPaM.GetPara() )
+ {
+ aPaM.GetPara()--;
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ aPaM.GetIndex() = pNode->GetText().Len();
+ }
+ return aPaM;
+}
+
+TextPaM TextView::CursorRight( const TextPaM& rPaM, BOOL bWordMode )
+{
+ TextPaM aPaM( rPaM );
+
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ if ( aPaM.GetIndex() < pNode->GetText().Len() )
+ {
+ uno::Reference < text::XBreakIterator > xBI = mpTextEngine->GetBreakIterator();
+ if ( bWordMode )
+ {
+ text::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES );
+ aPaM.GetIndex() = aBoundary.startPos;
+ }
+ else
+ {
+ sal_Int32 nCount = 1;
+ aPaM.GetIndex() = xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpTextEngine->GetLocale(), text::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
+ }
+ }
+ else if ( aPaM.GetPara() < ( mpTextEngine->mpDoc->GetNodes().Count()-1) )
+ {
+ aPaM.GetPara()++;
+ aPaM.GetIndex() = 0;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::ImpDelete( BYTE nMode, BYTE nDelMode )
+{
+ if ( maSelection.HasRange() ) // dann nur Sel. loeschen
+ return mpTextEngine->ImpDeleteText( maSelection );
+
+ TextPaM aStartPaM = maSelection.GetStart();
+ TextPaM aEndPaM = aStartPaM;
+ if ( nMode == DEL_LEFT )
+ {
+ if ( nDelMode == DELMODE_SIMPLE )
+ {
+ aEndPaM = CursorLeft( aEndPaM );
+ }
+ else if ( nDelMode == DELMODE_RESTOFWORD )
+ {
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ uno::Reference < text::XBreakIterator > xBI = mpTextEngine->GetBreakIterator();
+ text::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), maSelection.GetEnd().GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ if ( aBoundary.startPos == maSelection.GetEnd().GetIndex() )
+ aBoundary = xBI->previousWord( pNode->GetText(), maSelection.GetEnd().GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES );
+ aEndPaM.GetIndex() = aBoundary.startPos;
+ }
+ 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 );
+ }
+ else if ( nDelMode == DELMODE_RESTOFWORD )
+ {
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ uno::Reference < text::XBreakIterator > xBI = mpTextEngine->GetBreakIterator();
+ text::Boundary aBoundary = xBI->nextWord( pNode->GetText(), maSelection.GetEnd().GetIndex(), mpTextEngine->GetLocale(), text::WordType::ANYWORD_IGNOREWHITESPACES );
+ aEndPaM.GetIndex() = aBoundary.startPos;
+ }
+ else // DELMODE_RESTOFCONTENT
+ {
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ if ( aEndPaM.GetIndex() < pNode->GetText().Len() )
+ aEndPaM.GetIndex() = pNode->GetText().Len();
+ else if ( aEndPaM.GetPara() < ( mpTextEngine->mpDoc->GetNodes().Count() - 1 ) )
+ {
+ // Absatz danach
+ aEndPaM.GetPara()++;
+ TextNode* pNextNode = mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() );
+ aEndPaM.GetIndex() = pNextNode->GetText().Len();
+ }
+ }
+ }
+
+ return mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) );
+}
+
+
+
+TextPaM TextView::CursorUp( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ long nX;
+ if ( mnTravelXPos == TRAVEL_X_DONTKNOW )
+ {
+ nX = mpTextEngine->GetEditCursor( rPaM, FALSE ).Left();
+ mnTravelXPos = nX+1;
+ }
+ else
+ nX = mnTravelXPos;
+
+ TEParaPortion* pPPortion = mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), FALSE );
+ if ( nLine ) // gleicher Absatz
+ {
+ USHORT nCharPos = 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().GetObject( nLine - 1 );
+ if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) )
+ aPaM.GetIndex()--;
+ }
+ else if ( rPaM.GetPara() ) // vorheriger Absatz
+ {
+ aPaM.GetPara()--;
+ pPPortion = mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ USHORT nL = pPPortion->GetLines().Count() - 1;
+ USHORT nCharPos = mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 );
+ aPaM.GetIndex() = nCharPos;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::CursorDown( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ long nX;
+ if ( mnTravelXPos == TRAVEL_X_DONTKNOW )
+ {
+ nX = mpTextEngine->GetEditCursor( rPaM, FALSE ).Left();
+ mnTravelXPos = nX+1;
+ }
+ else
+ nX = mnTravelXPos;
+
+ TEParaPortion* pPPortion = mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), FALSE );
+ if ( nLine < ( pPPortion->GetLines().Count() - 1 ) )
+ {
+ USHORT nCharPos = mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX );
+ aPaM.GetIndex() = nCharPos;
+
+ // Sonderbehandlung siehe CursorUp...
+ TextLine* pLine = pPPortion->GetLines().GetObject( nLine + 1 );
+ if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() )
+ aPaM.GetIndex()--;
+ }
+ else if ( rPaM.GetPara() < ( mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz
+ {
+ aPaM.GetPara()++;
+ pPPortion = mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ USHORT nCharPos = mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 );
+ aPaM.GetIndex() = nCharPos;
+ TextLine* pLine = pPPortion->GetLines().GetObject( 0 );
+ if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().Count() > 1 ) )
+ aPaM.GetIndex()--;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ TEParaPortion* pPPortion = mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ USHORT nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), FALSE );
+ TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
+ aPaM.GetIndex() = pLine->GetStart();
+
+ return aPaM;
+}
+
+TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM )
+{
+ TextPaM aPaM( rPaM );
+
+ TEParaPortion* pPPortion = mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ USHORT nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), FALSE );
+ TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
+ aPaM.GetIndex() = pLine->GetEnd();
+
+ if ( pLine->GetEnd() > pLine->GetStart() ) // Leerzeile
+ {
+ xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((USHORT)(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 = 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()
+{
+ ULONG nNode = mpTextEngine->mpDoc->GetNodes().Count() - 1;
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( nNode );
+ TextPaM aPaM( nNode, pNode->GetText().Len() );
+ return aPaM;
+}
+
+TextPaM TextView::PageUp( const TextPaM& rPaM )
+{
+ Rectangle aRec = mpTextEngine->PaMtoEditCursor( rPaM );
+ Point aTopLeft = aRec.TopLeft();
+ aTopLeft.Y() -= mpWindow->GetOutputSizePixel().Height() * 9/10;
+ aTopLeft.X() += 1;
+ if ( aTopLeft.Y() < 0 )
+ aTopLeft.Y() = 0;
+
+ TextPaM aPaM = mpTextEngine->GetPaM( aTopLeft );
+ return aPaM;
+}
+
+TextPaM TextView::PageDown( const TextPaM& rPaM )
+{
+ Rectangle aRec = mpTextEngine->PaMtoEditCursor( rPaM );
+ Point aBottomRight = aRec.BottomRight();
+ aBottomRight.Y() += mpWindow->GetOutputSizePixel().Height() * 9/10;
+ aBottomRight.X() += 1;
+ long nHeight = mpTextEngine->GetTextHeight();
+ if ( aBottomRight.Y() > nHeight )
+ aBottomRight.Y() = nHeight-1;
+
+ TextPaM aPaM = mpTextEngine->GetPaM( aBottomRight );
+ return aPaM;
+}
+
+void TextView::ImpShowCursor( BOOL bGotoCursor, BOOL bForceVisCursor, BOOL bSpecial )
+{
+ if ( mpTextEngine->IsFormatting() )
+ return;
+ if ( mpTextEngine->GetUpdateMode() == FALSE )
+ return;
+ if ( mpTextEngine->IsInUndo() )
+ return;
+
+ mpTextEngine->CheckIdleFormatter();
+ if ( !mpTextEngine->IsFormatted() )
+ mpTextEngine->FormatAndUpdate( this );
+
+
+ TextPaM aPaM( maSelection.GetEnd() );
+ Rectangle aEditCursor = mpTextEngine->PaMtoEditCursor( aPaM, bSpecial );
+ if ( !IsInsertMode() && !maSelection.HasRange() )
+ {
+ TextNode* pNode = mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) )
+ {
+ long nWidth = (long)mpTextEngine->CalcTextWidth( aPaM.GetPara(), aPaM.GetIndex(), 1 );
+ aEditCursor.Right() += nWidth;
+ }
+ }
+
+ Size aOutSz = mpWindow->GetOutputSizePixel();
+ if ( aEditCursor.GetHeight() > aOutSz.Height() )
+ aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1;
+
+ if ( bGotoCursor )
+ {
+ long nVisStartY = maStartDocPos.Y();
+ long nVisEndY = maStartDocPos.Y() + aOutSz.Height();
+ long nVisStartX = maStartDocPos.X();
+ long nVisEndX = maStartDocPos.X() + aOutSz.Width();
+ long nMoreX = aOutSz.Width() / 4;
+
+ Point aNewStartPos( 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:
+// ULONG nMaxTextWidth = mpTextEngine->GetMaxTextWidth();
+// if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) )
+// nMaxTextWidth = 0x7FFFFFFF;
+// long nMaxX = (long)nMaxTextWidth - aOutSz.Width();
+ long nMaxX = 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 = mpTextEngine->GetTextHeight() - aOutSz.Height();
+ if ( nYMax < 0 )
+ nYMax = 0;
+ if ( aNewStartPos.Y() > nYMax )
+ aNewStartPos.Y() = nYMax;
+
+ if ( aNewStartPos != maStartDocPos )
+ {
+ Scroll( -(aNewStartPos.X() - maStartDocPos.X()), -(aNewStartPos.Y() - maStartDocPos.Y()) );
+ mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) );
+ }
+ }
+
+ Point aPoint( GetWindowPos( aEditCursor.TopLeft() ) );
+ mpCursor->SetPos( aPoint );
+ mpCursor->SetSize( aEditCursor.GetSize() );
+ if ( bForceVisCursor && mbCursorEnabled )
+ mpCursor->Show();
+}
+
+BOOL TextView::SetCursorAtPoint( const Point& rPosPixel )
+{
+// if ( !Rectangle( Point(), mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection )
+// return FALSE;
+
+ mpTextEngine->CheckIdleFormatter();
+
+ Point aDocPos = GetDocPos( rPosPixel );
+
+ TextPaM aPaM = mpTextEngine->GetPaM( aDocPos );
+
+ // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion
+ TextSelection aTmpNewSel( maSelection.GetEnd(), aPaM );
+ maSelection.GetEnd() = aPaM;
+
+ if ( !mpSelEngine->HasAnchor() )
+ {
+ if ( maSelection.GetStart() != aPaM )
+ mpTextEngine->CursorMoved( maSelection.GetStart().GetPara() );
+ maSelection.GetStart() = aPaM;
+ }
+ else
+ {
+ ShowSelection( aTmpNewSel );
+ }
+
+ BOOL bForceCursor = mpDDInfo ? FALSE : TRUE; // && !mbInSelection
+ ImpShowCursor( mbAutoScroll, bForceCursor, FALSE );
+ return TRUE;
+}
+
+BOOL TextView::IsSelectionAtPoint( const Point& rPosPixel )
+{
+// if ( !Rectangle( Point(), mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection )
+// return FALSE;
+
+ Point aDocPos = GetDocPos( rPosPixel );
+ TextPaM aPaM = mpTextEngine->GetPaM( aDocPos, 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 FALSE returnt wurde.
+ return ( IsInSelection( aPaM ) ||
+ ( /* mpSelEngine->IsInCommand() && */ mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) );
+}
+
+BOOL TextView::IsInSelection( const TextPaM& rPaM )
+{
+ TextSelection aSel = maSelection;
+ aSel.Justify();
+
+ ULONG nStartNode = aSel.GetStart().GetPara();
+ ULONG nEndNode = aSel.GetEnd().GetPara();
+ ULONG nCurNode = rPaM.GetPara();
+
+ if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) )
+ return TRUE;
+
+ if ( nStartNode == nEndNode )
+ {
+ if ( nCurNode == nStartNode )
+ if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
+ return TRUE;
+ }
+ else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) )
+ return TRUE;
+ else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+void TextView::ImpHideDDCursor()
+{
+ if ( mpDDInfo && mpDDInfo->mbVisCursor )
+ {
+ mpDDInfo->maCursor.Hide();
+ mpDDInfo->mbVisCursor = FALSE;
+ }
+}
+
+void TextView::ImpShowDDCursor()
+{
+ if ( !mpDDInfo->mbVisCursor )
+ {
+ Rectangle aCursor = mpTextEngine->PaMtoEditCursor( mpDDInfo->maDropPos, TRUE );
+ aCursor.Right()++;
+ aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) );
+
+ mpDDInfo->maCursor.SetWindow( mpWindow );
+ mpDDInfo->maCursor.SetPos( aCursor.TopLeft() );
+ mpDDInfo->maCursor.SetSize( aCursor.GetSize() );
+ mpDDInfo->maCursor.Show();
+ mpDDInfo->mbVisCursor = TRUE;
+ }
+}
+
+void TextView::BeginDrag()
+{
+ delete mpDDInfo;
+ mpDDInfo = new TextDDInfo;
+
+ mpDDInfo->mbStarterOfDD = TRUE;
+
+ DragServer::Clear();
+
+ TextSelection aSel( maSelection );
+ aSel.Justify();
+
+ // D&D eines Hyperlinks.
+ // Besser waere es im MBDown sich den MBDownPaM zu merken,
+ // ist dann aber inkompatibel => spaeter mal umstellen.
+ TextPaM aPaM( mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) );
+
+ const TextCharAttrib* pAttr = 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 = mpTextEngine->GetText( aSel );
+ INetBookmark aBookmark( rLink.GetURL(), aText );
+ aBookmark.CopyDragServer();
+ }
+
+ DragServer::CopyString( mpTextEngine->GetText( aSel ) );
+
+ Region* pDDRegion = NULL;
+#ifdef MAC
+ // ... Region ermitteln
+ Size aOutSz = mpWindow->GetOutputSizePixel();
+ Rectangle aStartCursor( mpTextEngine->GetEditCursor( aSel.GetStart(), FALSE ) );
+ Rectangle aEndCursor( mpTextEngine->GetEditCursor( aSel.GetEnd(), TRUE ) );
+
+ Point aTopLeft = aStartCursor.TopLeft();
+ aTopLeft -= maStartDocPos;
+
+ Point aBottomRight = aStartCursor.BottomRight();
+ aBottomRight -= maStartDocPos;
+
+ if ( aStartCursor.Top() != aEndCursor.Top() )
+ {
+ // Dann einfach das Rechteck mit den kompletten Zeilem
+ aTopLeft.X() = 0;
+ aBottomRight.X() = aOutSz.Width();
+ }
+
+ pDDRegion = new Region( Rectangle( aTopLeft, aBottomRight ) );
+#endif
+
+ mpCursor->Hide();
+
+ mpWindow->ExecuteDrag( Pointer( POINTER_MOVEDATA ),
+ Pointer( POINTER_COPYDATA ), DRAG_ALL, pDDRegion );
+
+ DragServer::Clear();
+ ImpHideDDCursor();
+
+ delete mpDDInfo;
+ mpDDInfo = 0;
+}
+
+BOOL TextView::QueryDrop( DropEvent& rEvt )
+{
+ if ( rEvt.IsLeaveWindow() )
+ {
+ ImpHideDDCursor();
+ return FALSE;
+ }
+
+ BOOL bDrop = FALSE;
+ if ( !mbReadOnly && DragServer::HasFormat( 0, FORMAT_STRING ) &&
+ ( ( rEvt.GetAction() == DROP_COPY ) || ( rEvt.GetAction() == DROP_MOVE ) ) )
+ {
+ if ( !mpDDInfo )
+ mpDDInfo = new TextDDInfo;
+
+ TextPaM aPrevDropPos = mpDDInfo->maDropPos;
+ Point aDocPos = GetDocPos( rEvt.GetPosPixel() );
+ mpDDInfo->maDropPos = mpTextEngine->GetPaM( aDocPos );
+
+ Size aOutSize = mpWindow->GetOutputSizePixel();
+ if ( ( rEvt.GetPosPixel().X() < 0 ) || ( rEvt.GetPosPixel().X() > aOutSize.Width() ) ||
+ ( rEvt.GetPosPixel().Y() < 0 ) || ( rEvt.GetPosPixel().Y() > aOutSize.Height() ) )
+ {
+ // Scrollen ?
+ }
+
+ // Nicht in Selektion droppen:
+ if ( IsInSelection( mpDDInfo->maDropPos ) )
+ {
+ ImpHideDDCursor();
+ return FALSE;
+ }
+
+ // Alten Cursor wegzeichnen...
+ if ( !mpDDInfo->mbVisCursor || ( aPrevDropPos != mpDDInfo->maDropPos ) )
+ {
+ ImpHideDDCursor();
+ ImpShowDDCursor();
+ }
+ bDrop = TRUE;
+ }
+ return bDrop;
+}
+
+BOOL TextView::Drop( const DropEvent& rEvt )
+{
+ BOOL bDone = FALSE;
+ if ( !mbReadOnly && mpDDInfo )
+ {
+ ImpHideDDCursor();
+
+ // Daten fuer das loeschen nach einem DROP_MOVE:
+ TextSelection aPrevSel( maSelection );
+ aPrevSel.Justify();
+ ULONG nPrevParaCount = mpTextEngine->GetParagraphCount();
+ USHORT nPrevStartParaLen = mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() );
+
+ BOOL bStarterOfDD = FALSE;
+ for ( USHORT nView = mpTextEngine->GetViewCount(); nView && !bStarterOfDD; )
+ bStarterOfDD = mpTextEngine->GetView( --nView )->mpDDInfo ? mpTextEngine->GetView( nView )->mpDDInfo->mbStarterOfDD : FALSE;
+
+ HideSelection();
+ maSelection = mpDDInfo->maDropPos;
+
+ mpTextEngine->UndoActionStart( TEXTUNDO_DRAGANDDROP );
+
+ String aText = DragServer::PasteString( 0 );
+ aText.ConvertLineEnd( LINEEND_LF );
+
+ if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) )
+ aText.Erase( aText.Len()-1 );
+
+ if ( ImplCheckTextLen( aText ) )
+ maSelection = mpTextEngine->ImpInsertText( mpDDInfo->maDropPos, aText );
+
+ if ( aPrevSel.HasRange() &&
+ ( rEvt.GetAction() == DROP_MOVE ) || !bStarterOfDD )
+ {
+ // ggf. Selection anpasssen:
+ if ( ( mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) ||
+ ( ( mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
+ && ( mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) )
+ {
+ ULONG nNewParasBeforeSelection =
+ mpTextEngine->GetParagraphCount() - nPrevParaCount;
+
+ aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection;
+ aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection;
+
+ if ( mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
+ {
+ USHORT nNewChars =
+ mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen;
+
+ aPrevSel.GetStart().GetIndex() += nNewChars;
+ if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() )
+ aPrevSel.GetEnd().GetIndex() += nNewChars;
+ }
+ }
+ else
+ {
+ // aktuelle Selektion anpassen
+ TextPaM aPaM = maSelection.GetStart();
+ aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() );
+ if ( aPrevSel.GetEnd().GetPara() == mpDDInfo->maDropPos.GetPara() )
+ {
+ aPaM.GetIndex() -= aPrevSel.GetEnd().GetIndex();
+ if ( aPrevSel.GetStart().GetPara() == mpDDInfo->maDropPos.GetPara() )
+ aPaM.GetIndex() += aPrevSel.GetStart().GetIndex();
+ }
+ maSelection = aPaM;
+
+ }
+ mpTextEngine->ImpDeleteText( aPrevSel );
+ }
+
+ mpTextEngine->UndoActionEnd( TEXTUNDO_DRAGANDDROP );
+
+ delete mpDDInfo;
+ mpDDInfo = 0;
+
+ mpTextEngine->FormatAndUpdate( this );
+
+ mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ }
+
+ return bDone;
+}
+
+void TextView::SetPaintSelection( BOOL bPaint )
+{
+ if ( bPaint != mbPaintSelection )
+ {
+ mbPaintSelection = bPaint;
+ ShowSelection( maSelection );
+ }
+}
+
+void TextView::SetHighlightSelection( BOOL bSelectByHighlight )
+{
+ if ( bSelectByHighlight != mbHighlightSelection )
+ {
+ // Falls umschalten zwischendurch moeglich...
+ mbHighlightSelection = bSelectByHighlight;
+ }
+}
+
+BOOL TextView::Read( SvStream& rInput )
+{
+ BOOL bDone = mpTextEngine->Read( rInput, &maSelection );
+ ShowCursor();
+ return bDone;
+}
+
+BOOL TextView::Write( SvStream& rOutput )
+{
+ return mpTextEngine->Read( rOutput, &maSelection );
+}
+
+BOOL TextView::ImplCheckTextLen( const String& rNewText )
+{
+ BOOL bOK = TRUE;
+ if ( mpTextEngine->GetMaxTextLen() )
+ {
+ ULONG n = mpTextEngine->GetTextLen();
+ n += rNewText.Len();
+ if ( n > mpTextEngine->GetMaxTextLen() )
+ {
+ // nur dann noch ermitteln, wie viel Text geloescht wird
+ n -= mpTextEngine->GetTextLen( maSelection );
+ if ( n > mpTextEngine->GetMaxTextLen() )
+ {
+ // Beep hat hier eigentlich nichts verloren, sondern lieber ein Hdl,
+ // aber so funktioniert es wenigstens in ME, BasicIDE, SourceView
+ Sound::Beep();
+ bOK = FALSE;
+ }
+ }
+ }
+ return bOK;
+}
+
+
+ // -------------------------------------------------------------------------
+// (+) class TextSelFunctionSet
+// -------------------------------------------------------------------------
+TextSelFunctionSet::TextSelFunctionSet( TextView* pView )
+{
+ mpView = pView;
+}
+
+void __EXPORT TextSelFunctionSet::BeginDrag()
+{
+ mpView->BeginDrag();
+}
+
+void __EXPORT TextSelFunctionSet::CreateAnchor()
+{
+// TextSelection aSel( mpView->GetSelection() );
+// aSel.GetStart() = aSel.GetEnd();
+// mpView->SetSelection( aSel );
+
+ // Es darf kein ShowCursor folgen:
+ mpView->HideSelection();
+ mpView->maSelection.GetStart() = mpView->maSelection.GetEnd();
+}
+
+BOOL __EXPORT TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, BOOL )
+{
+ return mpView->SetCursorAtPoint( rPointPixel );
+}
+
+BOOL __EXPORT TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
+{
+ return mpView->IsSelectionAtPoint( rPointPixel );
+}
+
+void __EXPORT TextSelFunctionSet::DeselectAll()
+{
+ CreateAnchor();
+}
+
+void __EXPORT TextSelFunctionSet::DeselectAtPoint( const Point& )
+{
+ // Nur bei Mehrfachselektion
+}
+
+void __EXPORT TextSelFunctionSet::DestroyAnchor()
+{
+ // Nur bei Mehrfachselektion
+}
+