summaryrefslogtreecommitdiff
path: root/svtools/source/edit
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/edit')
-rw-r--r--svtools/source/edit/editsyntaxhighlighter.cxx204
-rw-r--r--svtools/source/edit/makefile.mk63
-rw-r--r--svtools/source/edit/svmedit.cxx1656
-rw-r--r--svtools/source/edit/svmedit2.cxx81
-rw-r--r--svtools/source/edit/sychconv.cxx103
-rw-r--r--svtools/source/edit/syntaxhighlight.cxx909
-rw-r--r--svtools/source/edit/textdat2.hxx306
-rw-r--r--svtools/source/edit/textdata.cxx361
-rw-r--r--svtools/source/edit/textdoc.cxx1047
-rw-r--r--svtools/source/edit/textdoc.hxx148
-rw-r--r--svtools/source/edit/texteng.cxx3303
-rw-r--r--svtools/source/edit/textund2.hxx148
-rw-r--r--svtools/source/edit/textundo.cxx343
-rw-r--r--svtools/source/edit/textundo.hxx84
-rw-r--r--svtools/source/edit/textview.cxx2470
-rw-r--r--svtools/source/edit/textwindowpeer.cxx59
-rw-r--r--svtools/source/edit/txtattr.cxx197
-rw-r--r--svtools/source/edit/xtextedt.cxx421
18 files changed, 11903 insertions, 0 deletions
diff --git a/svtools/source/edit/editsyntaxhighlighter.cxx b/svtools/source/edit/editsyntaxhighlighter.cxx
new file mode 100644
index 000000000000..01bb7ad41682
--- /dev/null
+++ b/svtools/source/edit/editsyntaxhighlighter.cxx
@@ -0,0 +1,204 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/svmedit.hxx>
+#include <svtools/xtextedt.hxx>
+#include <svtools/editsyntaxhighlighter.hxx>
+#include "../../inc/txtattr.hxx"
+
+
+MultiLineEditSyntaxHighlight::MultiLineEditSyntaxHighlight( Window* pParent, WinBits nWinStyle,
+ HighlighterLanguage aLanguage): MultiLineEdit(pParent,nWinStyle), mbDoBracketHilight(true)
+{
+ EnableUpdateData(300);
+ aHighlighter.initialize( aLanguage );
+}
+
+MultiLineEditSyntaxHighlight::MultiLineEditSyntaxHighlight( Window* pParent, const ResId& rResId ,
+ HighlighterLanguage aLanguage): MultiLineEdit(pParent,rResId), mbDoBracketHilight(true)
+{
+ EnableUpdateData(300);
+ aHighlighter.initialize( aLanguage );
+}
+
+MultiLineEditSyntaxHighlight::~MultiLineEditSyntaxHighlight()
+{
+}
+
+void MultiLineEditSyntaxHighlight::EnableBracketHilight(bool aHilight)
+{
+ mbDoBracketHilight = aHilight;
+}
+
+bool MultiLineEditSyntaxHighlight::IsBracketHilight()
+{
+ return mbDoBracketHilight;
+}
+
+void MultiLineEditSyntaxHighlight::SetText(const String& rNewText)
+{
+ MultiLineEdit::SetText(rNewText);
+ UpdateData();
+}
+
+void MultiLineEditSyntaxHighlight::DoBracketHilight(USHORT aKey)
+{
+ TextSelection aCurrentPos = GetTextView()->GetSelection();
+ xub_StrLen aStartPos = aCurrentPos.GetStart().GetIndex();
+ ULONG nStartPara = aCurrentPos.GetStart().GetPara();
+ USHORT aCount = 0;
+ int aChar = -1;
+
+ switch (aKey)
+ {
+ case '\'': // no break
+ case '"':
+ {
+ aChar = aKey;
+ break;
+ }
+ case '}' :
+ {
+ aChar = '{';
+ break;
+ }
+ case ')':
+ {
+ aChar = '(';
+ break;
+ }
+ case ']':
+ {
+ aChar = '[';
+ break;
+ }
+ }
+
+ if (aChar != -1)
+ {
+ for (long aPara =nStartPara; aPara>=0;--aPara)
+ {
+ if ( aStartPos == 0 )
+ continue;
+
+ String aLine( GetTextEngine()->GetText( aPara ) );
+ for (USHORT i = ((unsigned long)aPara==nStartPara) ? aStartPos-1 : (USHORT)(aLine.Len()-1); i>0; --i)
+ {
+ if (aLine.GetChar(i)==aChar)
+ {
+ if (!aCount)
+ {
+ GetTextEngine()->SetAttrib( TextAttribFontWeight( WEIGHT_ULTRABOLD ), aPara, i, i+1, TRUE );
+ GetTextEngine()->SetAttrib( TextAttribFontColor( Color(0,0,0) ), aPara, i, i+1, TRUE );
+ GetTextEngine()->SetAttrib( TextAttribFontWeight( WEIGHT_ULTRABOLD ), nStartPara, aStartPos, aStartPos, TRUE );
+ GetTextEngine()->SetAttrib( TextAttribFontColor( Color(0,0,0) ), nStartPara, aStartPos, aStartPos, TRUE );
+ return;
+ }
+ else
+ aCount--;
+ }
+ if (aLine.GetChar(i)==aKey)
+ aCount++;
+ }
+ }
+ }
+}
+
+long MultiLineEditSyntaxHighlight::PreNotify( NotifyEvent& rNEvt )
+{
+ if ( mbDoBracketHilight && (rNEvt.GetType() == EVENT_KEYINPUT) )
+ DoBracketHilight(rNEvt.GetKeyEvent()->GetCharCode());
+
+ return MultiLineEdit::PreNotify(rNEvt);
+}
+
+Color MultiLineEditSyntaxHighlight::GetColorValue(TokenTypes aToken)
+{
+ Color aColor;
+ switch (aHighlighter.GetLanguage())
+ {
+ case HIGHLIGHT_SQL:
+ {
+ switch (aToken)
+ {
+ case TT_IDENTIFIER: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLIDENTIFIER).nColor; break;
+ case TT_NUMBER: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLNUMBER).nColor; break;
+ case TT_STRING: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLSTRING).nColor; break;
+ case TT_OPERATOR: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLOPERATOR).nColor; break;
+ case TT_KEYWORDS: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLKEYWORD).nColor; break;
+ case TT_PARAMETER: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLPARAMETER).nColor; break;
+ case TT_COMMENT: aColor = (ColorData)m_aColorConfig.GetColorValue(svtools::SQLCOMMENT).nColor; break;
+ default: aColor = Color(0,0,0);
+ }
+ break;
+ }
+ case HIGHLIGHT_BASIC:
+ {
+ switch (aToken)
+ {
+ case TT_IDENTIFIER: aColor = Color(255,0,0); break;
+ case TT_COMMENT: aColor = Color(0,0,45); break;
+ case TT_NUMBER: aColor = Color(204,102,204); break;
+ case TT_STRING: aColor = Color(0,255,45); break;
+ case TT_OPERATOR: aColor = Color(0,0,100); break;
+ case TT_KEYWORDS: aColor = Color(0,0,255); break;
+ case TT_ERROR : aColor = Color(0,255,255); break;
+ default: aColor = Color(0,0,0);
+ }
+ break;
+ }
+ default: aColor = Color(0,0,0);
+
+ }
+ return aColor;
+}
+
+void MultiLineEditSyntaxHighlight::UpdateData()
+{
+ // syntax highlighting
+ // this must be possible improved by using notifychange correctly
+ BOOL bTempModified = GetTextEngine()->IsModified();
+ for (unsigned int nLine=0; nLine < GetTextEngine()->GetParagraphCount(); nLine++)
+ {
+ String aLine( GetTextEngine()->GetText( nLine ) );
+ Range aChanges = aHighlighter.notifyChange( nLine, 0, &aLine, 1 );
+
+ GetTextEngine()->RemoveAttribs( nLine, TRUE );
+ HighlightPortions aPortions;
+ aHighlighter.getHighlightPortions( nLine, aLine, aPortions );
+ for ( USHORT i = 0; i < aPortions.Count(); i++ )
+ {
+ HighlightPortion& r = aPortions[i];
+ GetTextEngine()->SetAttrib( TextAttribFontColor( GetColorValue(r.tokenType) ), nLine, r.nBegin, r.nEnd, TRUE );
+ }
+ }
+ GetTextView()->ShowCursor( false, true );
+ GetTextEngine()->SetModified(bTempModified);
+}
diff --git a/svtools/source/edit/makefile.mk b/svtools/source/edit/makefile.mk
new file mode 100644
index 000000000000..58a63be58f78
--- /dev/null
+++ b/svtools/source/edit/makefile.mk
@@ -0,0 +1,63 @@
+#*************************************************************************
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=svtools
+TARGET=edit
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/svt.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= \
+ $(SLO)$/textdata.obj \
+ $(SLO)$/textdoc.obj \
+ $(SLO)$/texteng.obj \
+ $(SLO)$/textundo.obj \
+ $(SLO)$/textview.obj \
+ $(SLO)$/txtattr.obj \
+ $(SLO)$/xtextedt.obj \
+ $(SLO)$/sychconv.obj \
+ $(SLO)$/svmedit.obj \
+ $(SLO)$/svmedit2.obj \
+ $(SLO)$/textwindowpeer.obj \
+ $(SLO)$/syntaxhighlight.obj \
+ $(SLO)$/editsyntaxhighlighter.obj
+
+EXCEPTIONSFILES= \
+ $(SLO)$/textview.obj \
+ $(SLO)$/textdoc.obj \
+ $(SLO)$/texteng.obj \
+ $(SLO)$/textwindowpeer.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/svtools/source/edit/svmedit.cxx b/svtools/source/edit/svmedit.cxx
new file mode 100644
index 000000000000..daaff472d1cc
--- /dev/null
+++ b/svtools/source/edit/svmedit.cxx
@@ -0,0 +1,1656 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+
+#include <memory>
+
+#include "unoiface.hxx"
+
+#include <tools/rc.h>
+
+#include <vcl/decoview.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svtools/svmedit.hxx>
+#include <svtools/xtextedt.hxx>
+#include <svl/brdcst.hxx>
+#include <svl/undo.hxx>
+#include <svtools/textwindowpeer.hxx>
+#include <svl/lstner.hxx>
+#include <svl/smplhint.hxx>
+
+
+// IDs erstmal aus VCL geklaut, muss mal richtig delivert werden...
+#define SV_MENU_EDIT_UNDO 1
+#define SV_MENU_EDIT_CUT 2
+#define SV_MENU_EDIT_COPY 3
+#define SV_MENU_EDIT_PASTE 4
+#define SV_MENU_EDIT_DELETE 5
+#define SV_MENU_EDIT_SELECTALL 6
+#define SV_MENU_EDIT_INSERTSYMBOL 7
+#include <vcl/scrbar.hxx>
+
+namespace css = ::com::sun::star;
+
+class TextWindow : public Window
+{
+private:
+ ExtTextEngine* mpExtTextEngine;
+ ExtTextView* mpExtTextView;
+
+ BOOL mbInMBDown;
+ BOOL mbFocusSelectionHide;
+ BOOL mbIgnoreTab;
+ BOOL mbActivePopup;
+ BOOL mbSelectOnTab;
+
+public:
+ TextWindow( Window* pParent );
+ ~TextWindow();
+
+ ExtTextEngine* GetTextEngine() const { return mpExtTextEngine; }
+ ExtTextView* GetTextView() const { return mpExtTextView; }
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvent );
+
+ virtual void Command( const CommandEvent& rCEvt );
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+
+ virtual void GetFocus();
+ virtual void LoseFocus();
+
+ BOOL IsAutoFocusHide() const { return mbFocusSelectionHide; }
+ void SetAutoFocusHide( BOOL bAutoHide ) { mbFocusSelectionHide = bAutoHide; }
+
+ BOOL IsIgnoreTab() const { return mbIgnoreTab; }
+ void SetIgnoreTab( BOOL bIgnore ) { mbIgnoreTab = bIgnore; }
+
+ void DisableSelectionOnFocus() {mbSelectOnTab = sal_False;}
+
+ virtual
+ ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer >
+ GetComponentInterface(BOOL bCreate = TRUE);
+};
+
+
+class ImpSvMEdit : public SfxListener
+{
+private:
+ MultiLineEdit* pSvMultiLineEdit;
+
+ TextWindow* mpTextWindow;
+ ScrollBar* mpHScrollBar;
+ ScrollBar* mpVScrollBar;
+ ScrollBarBox* mpScrollBox;
+
+ Point maTextWindowOffset;
+ xub_StrLen mnTextWidth;
+ mutable Selection maSelection;
+
+protected:
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
+ void ImpUpdateSrollBarVis( WinBits nWinStyle );
+ void ImpInitScrollBars();
+ void ImpSetScrollBarRanges();
+ void ImpSetHScrollBarThumbPos();
+ DECL_LINK( ScrollHdl, ScrollBar* );
+
+public:
+ ImpSvMEdit( MultiLineEdit* pSvMultiLineEdit, WinBits nWinStyle );
+ ~ImpSvMEdit();
+
+ void SetModified( BOOL bMod );
+ BOOL IsModified() const;
+
+ void SetReadOnly( BOOL bRdOnly );
+ BOOL IsReadOnly() const;
+
+ void SetMaxTextLen( xub_StrLen nLen );
+ xub_StrLen GetMaxTextLen() const;
+
+ void SetInsertMode( BOOL bInsert );
+ BOOL IsInsertMode() const;
+
+ void InsertText( const String& rStr );
+ String GetSelected() const;
+ String GetSelected( LineEnd aSeparator ) const;
+
+ void SetSelection( const Selection& rSelection );
+ const Selection& GetSelection() const;
+
+ void Cut();
+ void Copy();
+ void Paste();
+
+ void SetText( const String& rStr );
+ String GetText() const;
+ String GetText( LineEnd aSeparator ) const;
+ String GetTextLines() const;
+ String GetTextLines( LineEnd aSeparator ) const;
+
+ void Resize();
+ void GetFocus();
+
+ BOOL HandleCommand( const CommandEvent& rCEvt );
+
+ void Enable( BOOL bEnable );
+
+ Size CalcMinimumSize() const;
+ Size CalcSize( USHORT nColumns, USHORT nLines ) const;
+ void GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const;
+
+ void SetAlign( WinBits nWinStyle );
+
+ void InitFromStyle( WinBits nWinStyle );
+
+ TextWindow* GetTextWindow() { return mpTextWindow; }
+ ScrollBar* GetHScrollBar() { return mpHScrollBar; }
+ ScrollBar* GetVScrollBar() { return mpVScrollBar; }
+
+ void SetTextWindowOffset( const Point& rOffset );
+};
+
+ImpSvMEdit::ImpSvMEdit( MultiLineEdit* pEdt, WinBits nWinStyle )
+ :mpHScrollBar(NULL)
+ ,mpVScrollBar(NULL)
+ ,mpScrollBox(NULL)
+{
+ pSvMultiLineEdit = pEdt;
+ mnTextWidth = 0;
+ mpTextWindow = new TextWindow( pEdt );
+ mpTextWindow->Show();
+ InitFromStyle( nWinStyle );
+ StartListening( *mpTextWindow->GetTextEngine() );
+}
+
+void ImpSvMEdit::ImpUpdateSrollBarVis( WinBits nWinStyle )
+{
+ const BOOL bHaveVScroll = (NULL != mpVScrollBar);
+ const BOOL bHaveHScroll = (NULL != mpHScrollBar);
+ const BOOL bHaveScrollBox = (NULL != mpScrollBox);
+
+ BOOL bNeedVScroll = ( nWinStyle & WB_VSCROLL ) == WB_VSCROLL;
+ const BOOL bNeedHScroll = ( nWinStyle & WB_HSCROLL ) == WB_HSCROLL;
+
+ const BOOL bAutoVScroll = ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL;
+ if ( !bNeedVScroll && bAutoVScroll )
+ {
+ TextEngine& rEngine( *mpTextWindow->GetTextEngine() );
+ ULONG nOverallTextHeight(0);
+ for ( ULONG i=0; i<rEngine.GetParagraphCount(); ++i )
+ nOverallTextHeight += rEngine.GetTextHeight( i );
+ if ( nOverallTextHeight > (ULONG)mpTextWindow->GetOutputSizePixel().Height() )
+ bNeedVScroll = true;
+ }
+
+ const BOOL bNeedScrollBox = bNeedVScroll && bNeedHScroll;
+
+ BOOL bScrollbarsChanged = false;
+ if ( bHaveVScroll != bNeedVScroll )
+ {
+ delete mpVScrollBar;
+ mpVScrollBar = bNeedVScroll ? new ScrollBar( pSvMultiLineEdit, WB_VSCROLL|WB_DRAG ) : NULL;
+
+ if ( bNeedVScroll )
+ {
+ mpVScrollBar->Show();
+ mpVScrollBar->SetScrollHdl( LINK( this, ImpSvMEdit, ScrollHdl ) );
+ }
+
+ bScrollbarsChanged = sal_True;
+ }
+
+ if ( bHaveHScroll != bNeedHScroll )
+ {
+ delete mpHScrollBar;
+ mpHScrollBar = bNeedHScroll ? new ScrollBar( pSvMultiLineEdit, WB_HSCROLL|WB_DRAG ) : NULL;
+
+ if ( bNeedHScroll )
+ {
+ mpHScrollBar->Show();
+ mpHScrollBar->SetScrollHdl( LINK( this, ImpSvMEdit, ScrollHdl ) );
+ }
+
+ bScrollbarsChanged = sal_True;
+ }
+
+ if ( bHaveScrollBox != bNeedScrollBox )
+ {
+ delete mpScrollBox;
+ mpScrollBox = bNeedScrollBox ? new ScrollBarBox( pSvMultiLineEdit, WB_SIZEABLE ) : NULL;
+
+ if ( bNeedScrollBox )
+ mpScrollBox->Show();
+ }
+
+ if ( bScrollbarsChanged )
+ {
+ ImpInitScrollBars();
+ Resize();
+ }
+}
+
+void ImpSvMEdit::InitFromStyle( WinBits nWinStyle )
+{
+ ImpUpdateSrollBarVis( nWinStyle );
+ SetAlign( nWinStyle );
+
+ if ( nWinStyle & WB_NOHIDESELECTION )
+ mpTextWindow->SetAutoFocusHide( FALSE );
+ else
+ mpTextWindow->SetAutoFocusHide( TRUE );
+
+ if ( nWinStyle & WB_READONLY )
+ mpTextWindow->GetTextView()->SetReadOnly( TRUE );
+ else
+ mpTextWindow->GetTextView()->SetReadOnly( FALSE );
+
+ if ( nWinStyle & WB_IGNORETAB )
+ {
+ mpTextWindow->SetIgnoreTab( TRUE );
+ }
+ else
+ {
+ mpTextWindow->SetIgnoreTab( FALSE );
+ // #103667# MultiLineEdit has the flag, but focusable window also needs this flag
+ WinBits nStyle = mpTextWindow->GetStyle();
+ nStyle |= WINDOW_DLGCTRL_MOD1TAB;
+ mpTextWindow->SetStyle( nStyle );
+ }
+}
+
+ImpSvMEdit::~ImpSvMEdit()
+{
+ EndListening( *mpTextWindow->GetTextEngine() );
+ delete mpTextWindow;
+ delete mpHScrollBar;
+ delete mpVScrollBar;
+ delete mpScrollBox;
+}
+
+void ImpSvMEdit::ImpSetScrollBarRanges()
+{
+ if ( mpVScrollBar )
+ {
+ ULONG nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight();
+ mpVScrollBar->SetRange( Range( 0, (long)nTextHeight-1 ) );
+ }
+ if ( mpHScrollBar )
+ {
+// ULONG nTextWidth = mpTextWindow->GetTextEngine()->CalcTextWidth();
+ // Es gibt kein Notify bei Breiten-Aenderung...
+// ULONG nW = Max( (ULONG)mpTextWindow->GetOutputSizePixel().Width()*5, (ULONG)nTextWidth );
+// mpHScrollBar->SetRange( Range( 0, (long)nW ) );
+ mpHScrollBar->SetRange( Range( 0, (long)mnTextWidth-1 ) );
+ }
+}
+
+void ImpSvMEdit::ImpInitScrollBars()
+{
+ static const sal_Unicode sampleText[] = { 'x', '\0' };
+ if ( mpHScrollBar || mpVScrollBar )
+ {
+ ImpSetScrollBarRanges();
+ Size aCharBox;
+ aCharBox.Width() = mpTextWindow->GetTextWidth( sampleText );
+ aCharBox.Height() = mpTextWindow->GetTextHeight();
+ Size aOutSz = mpTextWindow->GetOutputSizePixel();
+ if ( mpHScrollBar )
+ {
+ mpHScrollBar->SetVisibleSize( aOutSz.Width() );
+ mpHScrollBar->SetPageSize( aOutSz.Width() * 8 / 10 );
+ mpHScrollBar->SetLineSize( aCharBox.Width()*10 );
+ ImpSetHScrollBarThumbPos();
+ }
+ if ( mpVScrollBar )
+ {
+ mpVScrollBar->SetVisibleSize( aOutSz.Height() );
+ mpVScrollBar->SetPageSize( aOutSz.Height() * 8 / 10 );
+ mpVScrollBar->SetLineSize( aCharBox.Height() );
+ mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() );
+ }
+ }
+}
+
+void ImpSvMEdit::ImpSetHScrollBarThumbPos()
+{
+ long nX = mpTextWindow->GetTextView()->GetStartDocPos().X();
+ if ( !mpTextWindow->GetTextEngine()->IsRightToLeft() )
+ mpHScrollBar->SetThumbPos( nX );
+ else
+ mpHScrollBar->SetThumbPos( mnTextWidth - mpHScrollBar->GetVisibleSize() - nX );
+
+}
+
+IMPL_LINK( ImpSvMEdit, ScrollHdl, ScrollBar*, pCurScrollBar )
+{
+ long nDiffX = 0, nDiffY = 0;
+
+ if ( pCurScrollBar == mpVScrollBar )
+ nDiffY = mpTextWindow->GetTextView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos();
+ else if ( pCurScrollBar == mpHScrollBar )
+ nDiffX = mpTextWindow->GetTextView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos();
+
+ mpTextWindow->GetTextView()->Scroll( nDiffX, nDiffY );
+ // mpTextWindow->GetTextView()->ShowCursor( FALSE, TRUE );
+
+ return 0;
+}
+
+
+// void ImpSvMEdit::ImpModified()
+// {
+// // Wann wird das gerufen ?????????????????????
+// pSvMultiLineEdit->Modify();
+// }
+
+void ImpSvMEdit::SetAlign( WinBits nWinStyle )
+{
+ BOOL bRTL = Application::GetSettings().GetLayoutRTL();
+ mpTextWindow->GetTextEngine()->SetRightToLeft( bRTL );
+
+ if ( nWinStyle & WB_CENTER )
+ mpTextWindow->GetTextEngine()->SetTextAlign( TXTALIGN_CENTER );
+ else if ( nWinStyle & WB_RIGHT )
+ mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TXTALIGN_RIGHT : TXTALIGN_LEFT );
+ else if ( nWinStyle & WB_LEFT )
+ mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TXTALIGN_LEFT : TXTALIGN_RIGHT );
+}
+
+void ImpSvMEdit::SetTextWindowOffset( const Point& rOffset )
+{
+ maTextWindowOffset = rOffset;
+ Resize();
+}
+
+void ImpSvMEdit::SetModified( BOOL bMod )
+{
+ mpTextWindow->GetTextEngine()->SetModified( bMod );
+}
+
+BOOL ImpSvMEdit::IsModified() const
+{
+ return mpTextWindow->GetTextEngine()->IsModified();
+}
+
+void ImpSvMEdit::SetInsertMode( BOOL bInsert )
+{
+ mpTextWindow->GetTextView()->SetInsertMode( bInsert );
+}
+
+void ImpSvMEdit::SetReadOnly( BOOL bRdOnly )
+{
+ mpTextWindow->GetTextView()->SetReadOnly( bRdOnly );
+ // Farbe anpassen ???????????????????????????
+}
+
+BOOL ImpSvMEdit::IsReadOnly() const
+{
+ return mpTextWindow->GetTextView()->IsReadOnly();
+}
+
+void ImpSvMEdit::SetMaxTextLen( xub_StrLen nLen )
+{
+ mpTextWindow->GetTextEngine()->SetMaxTextLen( nLen );
+}
+
+xub_StrLen ImpSvMEdit::GetMaxTextLen() const
+{
+ return sal::static_int_cast< xub_StrLen >(
+ mpTextWindow->GetTextEngine()->GetMaxTextLen());
+}
+
+void ImpSvMEdit::InsertText( const String& rStr )
+{
+ mpTextWindow->GetTextView()->InsertText( rStr );
+}
+
+String ImpSvMEdit::GetSelected() const
+{
+ return mpTextWindow->GetTextView()->GetSelected();
+}
+
+String ImpSvMEdit::GetSelected( LineEnd aSeparator ) const
+{
+ return mpTextWindow->GetTextView()->GetSelected( aSeparator );
+}
+
+void ImpSvMEdit::Resize()
+{
+ size_t nIteration = 1;
+ do
+ {
+ WinBits nWinStyle( pSvMultiLineEdit->GetStyle() );
+ if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL )
+ ImpUpdateSrollBarVis( nWinStyle );
+
+ Size aSz = pSvMultiLineEdit->GetOutputSizePixel();
+ Size aEditSize = aSz;
+ long nSBWidth = pSvMultiLineEdit->GetSettings().GetStyleSettings().GetScrollBarSize();
+ nSBWidth = pSvMultiLineEdit->CalcZoom( nSBWidth );
+
+ if ( mpHScrollBar )
+ aSz.Height() -= nSBWidth+1;
+ if ( mpVScrollBar )
+ aSz.Width() -= nSBWidth+1;
+
+ if ( !mpHScrollBar )
+ mpTextWindow->GetTextEngine()->SetMaxTextWidth( aSz.Width() );
+ else
+ mpHScrollBar->SetPosSizePixel( 0, aEditSize.Height()-nSBWidth, aSz.Width(), nSBWidth );
+
+ Point aTextWindowPos( maTextWindowOffset );
+ if ( mpVScrollBar )
+ {
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ mpVScrollBar->SetPosSizePixel( 0, 0, nSBWidth, aSz.Height() );
+ aTextWindowPos.X() += nSBWidth;
+ }
+ else
+ mpVScrollBar->SetPosSizePixel( aEditSize.Width()-nSBWidth, 0, nSBWidth, aSz.Height() );
+ }
+
+ if ( mpScrollBox )
+ mpScrollBox->SetPosSizePixel( aSz.Width(), aSz.Height(), nSBWidth, nSBWidth );
+
+ Size aTextWindowSize( aSz );
+ aTextWindowSize.Width() -= maTextWindowOffset.X();
+ aTextWindowSize.Height() -= maTextWindowOffset.Y();
+ if ( aTextWindowSize.Width() < 0 )
+ aTextWindowSize.Width() = 0;
+ if ( aTextWindowSize.Height() < 0 )
+ aTextWindowSize.Height() = 0;
+
+ Size aOldTextWindowSize( mpTextWindow->GetSizePixel() );
+ mpTextWindow->SetPosSizePixel( aTextWindowPos, aTextWindowSize );
+ if ( aOldTextWindowSize == aTextWindowSize )
+ break;
+
+ // Changing the text window size might effectively have changed the need for
+ // scrollbars, so do another iteration.
+ ++nIteration;
+ OSL_ENSURE( nIteration < 3, "ImpSvMEdit::Resize: isn't this expected to terminate with the second iteration?" );
+
+ } while ( nIteration <= 3 ); // artificial break after four iterations
+
+ ImpInitScrollBars();
+}
+
+void ImpSvMEdit::GetFocus()
+{
+ mpTextWindow->GrabFocus();
+}
+
+void ImpSvMEdit::Cut()
+{
+ if ( !mpTextWindow->GetTextView()->IsReadOnly() )
+ mpTextWindow->GetTextView()->Cut();
+}
+
+void ImpSvMEdit::Copy()
+{
+ mpTextWindow->GetTextView()->Copy();
+}
+
+void ImpSvMEdit::Paste()
+{
+ if ( !mpTextWindow->GetTextView()->IsReadOnly() )
+ mpTextWindow->GetTextView()->Paste();
+}
+
+void ImpSvMEdit::SetText( const String& rStr )
+{
+ BOOL bWasModified = mpTextWindow->GetTextEngine()->IsModified();
+ mpTextWindow->GetTextEngine()->SetText( rStr );
+ if ( !bWasModified )
+ mpTextWindow->GetTextEngine()->SetModified( FALSE );
+
+ mpTextWindow->GetTextView()->SetSelection( TextSelection() );
+
+ WinBits nWinStyle( pSvMultiLineEdit->GetStyle() );
+ if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL )
+ ImpUpdateSrollBarVis( nWinStyle );
+}
+
+String ImpSvMEdit::GetText() const
+{
+ return mpTextWindow->GetTextEngine()->GetText();
+}
+
+String ImpSvMEdit::GetText( LineEnd aSeparator ) const
+{
+ return mpTextWindow->GetTextEngine()->GetText( aSeparator );
+}
+
+String ImpSvMEdit::GetTextLines() const
+{
+ return mpTextWindow->GetTextEngine()->GetTextLines();
+}
+
+String ImpSvMEdit::GetTextLines( LineEnd aSeparator ) const
+{
+ return mpTextWindow->GetTextEngine()->GetTextLines( aSeparator );
+}
+
+void ImpSvMEdit::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.ISA( TextHint ) )
+ {
+ const TextHint& rTextHint = (const TextHint&)rHint;
+ if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED )
+ {
+ if ( mpHScrollBar )
+ ImpSetHScrollBarThumbPos();
+ if ( mpVScrollBar )
+ mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() );
+ }
+ else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED )
+ {
+ if ( mpTextWindow->GetTextView()->GetStartDocPos().Y() )
+ {
+ long nOutHeight = mpTextWindow->GetOutputSizePixel().Height();
+ long nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight();
+ if ( nTextHeight < nOutHeight )
+ mpTextWindow->GetTextView()->Scroll( 0, mpTextWindow->GetTextView()->GetStartDocPos().Y() );
+ }
+
+ ImpSetScrollBarRanges();
+ }
+ else if( rTextHint.GetId() == TEXT_HINT_TEXTFORMATTED )
+ {
+ if ( mpHScrollBar )
+ {
+ ULONG nWidth = mpTextWindow->GetTextEngine()->CalcTextWidth();
+ if ( nWidth != mnTextWidth )
+ {
+ mnTextWidth = sal::static_int_cast< xub_StrLen >(nWidth);
+ mpHScrollBar->SetRange( Range( 0, (long)mnTextWidth-1 ) );
+ ImpSetHScrollBarThumbPos();
+ }
+ }
+ }
+ else if( rTextHint.GetId() == TEXT_HINT_MODIFIED )
+ {
+ pSvMultiLineEdit->Modify();
+ }
+ }
+}
+
+void ImpSvMEdit::SetSelection( const Selection& rSelection )
+{
+ String aText = mpTextWindow->GetTextEngine()->GetText();
+
+ Selection aNewSelection( rSelection );
+ if ( aNewSelection.Min() < 0 )
+ aNewSelection.Min() = 0;
+ else if ( aNewSelection.Min() > aText.Len() )
+ aNewSelection.Min() = aText.Len();
+ if ( aNewSelection.Max() < 0 )
+ aNewSelection.Max() = 0;
+ else if ( aNewSelection.Max() > aText.Len() )
+ aNewSelection.Max() = aText.Len();
+
+ long nEnd = Max( aNewSelection.Min(), aNewSelection.Max() );
+ TextSelection aTextSel;
+ ULONG nPara = 0;
+ USHORT nChar = 0;
+ USHORT x = 0;
+ while ( x <= nEnd )
+ {
+ if ( x == aNewSelection.Min() )
+ aTextSel.GetStart() = TextPaM( nPara, nChar );
+ if ( x == aNewSelection.Max() )
+ aTextSel.GetEnd() = TextPaM( nPara, nChar );
+
+ if ( ( x < aText.Len() ) && ( aText.GetChar( x ) == '\n' ) )
+ {
+ nPara++;
+ nChar = 0;
+ }
+ else
+ nChar++;
+ x++;
+ }
+ mpTextWindow->GetTextView()->SetSelection( aTextSel );
+}
+
+const Selection& ImpSvMEdit::GetSelection() const
+{
+ maSelection = Selection();
+ TextSelection aTextSel( mpTextWindow->GetTextView()->GetSelection() );
+ aTextSel.Justify();
+ // Selektion flachklopfen => jeder Umbruch ein Zeichen...
+
+ ExtTextEngine* pExtTextEngine = mpTextWindow->GetTextEngine();
+ // Absaetze davor:
+ ULONG n;
+ for ( n = 0; n < aTextSel.GetStart().GetPara(); n++ )
+ {
+ maSelection.Min() += pExtTextEngine->GetTextLen( n );
+ maSelection.Min()++;
+ }
+
+ // Erster Absatz mit Selektion:
+ maSelection.Max() = maSelection.Min();
+ maSelection.Min() += aTextSel.GetStart().GetIndex();
+
+ for ( n = aTextSel.GetStart().GetPara(); n < aTextSel.GetEnd().GetPara(); n++ )
+ {
+ maSelection.Max() += pExtTextEngine->GetTextLen( n );
+ maSelection.Max()++;
+ }
+
+ maSelection.Max() += aTextSel.GetEnd().GetIndex();
+
+ return maSelection;
+}
+
+Size ImpSvMEdit::CalcMinimumSize() const
+{
+ Size aSz( mpTextWindow->GetTextEngine()->CalcTextWidth(),
+ mpTextWindow->GetTextEngine()->GetTextHeight() );
+
+ if ( mpHScrollBar )
+ aSz.Height() += mpHScrollBar->GetSizePixel().Height();
+ if ( mpVScrollBar )
+ aSz.Width() += mpVScrollBar->GetSizePixel().Width();
+
+ return aSz;
+}
+
+Size ImpSvMEdit::CalcSize( USHORT nColumns, USHORT nLines ) const
+{
+ static const sal_Unicode sampleText[] = { 'X', '\0' };
+
+ Size aSz;
+ Size aCharSz;
+ aCharSz.Width() = mpTextWindow->GetTextWidth( sampleText );
+ aCharSz.Height() = mpTextWindow->GetTextHeight();
+
+ if ( nLines )
+ aSz.Height() = nLines*aCharSz.Height();
+ else
+ aSz.Height() = mpTextWindow->GetTextEngine()->GetTextHeight();
+
+ if ( nColumns )
+ aSz.Width() = nColumns*aCharSz.Width();
+ else
+ aSz.Width() = mpTextWindow->GetTextEngine()->CalcTextWidth();
+
+ if ( mpHScrollBar )
+ aSz.Height() += mpHScrollBar->GetSizePixel().Height();
+ if ( mpVScrollBar )
+ aSz.Width() += mpVScrollBar->GetSizePixel().Width();
+
+ return aSz;
+}
+
+void ImpSvMEdit::GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const
+{
+ static const sal_Unicode sampleText[] = { 'x', '\0' };
+ Size aOutSz = mpTextWindow->GetOutputSizePixel();
+ Size aCharSz( mpTextWindow->GetTextWidth( sampleText ), mpTextWindow->GetTextHeight() );
+ rnCols = (USHORT) (aOutSz.Width()/aCharSz.Width());
+ rnLines = (USHORT) (aOutSz.Height()/aCharSz.Height());
+}
+
+void ImpSvMEdit::Enable( BOOL bEnable )
+{
+ mpTextWindow->Enable( bEnable );
+ if ( mpHScrollBar )
+ mpHScrollBar->Enable( bEnable );
+ if ( mpVScrollBar )
+ mpVScrollBar->Enable( bEnable );
+}
+
+BOOL ImpSvMEdit::HandleCommand( const CommandEvent& rCEvt )
+{
+ BOOL bDone = FALSE;
+ if ( ( rCEvt.GetCommand() == COMMAND_WHEEL ) ||
+ ( rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL ) ||
+ ( rCEvt.GetCommand() == COMMAND_AUTOSCROLL ) )
+ {
+ mpTextWindow->HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
+ bDone = TRUE;
+ }
+ return bDone;
+}
+
+
+TextWindow::TextWindow( Window* pParent ) : Window( pParent )
+{
+ mbInMBDown = FALSE;
+ mbSelectOnTab = TRUE;
+ mbFocusSelectionHide = FALSE;
+ mbIgnoreTab = FALSE;
+ mbActivePopup = FALSE;
+ mbSelectOnTab = TRUE;
+
+ SetPointer( Pointer( POINTER_TEXT ) );
+
+ mpExtTextEngine = new ExtTextEngine;
+ mpExtTextEngine->SetMaxTextLen( STRING_MAXLEN );
+ if( pParent->GetStyle() & WB_BORDER )
+ mpExtTextEngine->SetLeftMargin( 2 );
+ mpExtTextEngine->SetLocale( GetSettings().GetLocale() );
+ mpExtTextView = new ExtTextView( mpExtTextEngine, this );
+ mpExtTextEngine->InsertView( mpExtTextView );
+ mpExtTextEngine->EnableUndo( TRUE );
+ mpExtTextView->ShowCursor();
+
+ Color aBackgroundColor = GetSettings().GetStyleSettings().GetWorkspaceColor();
+ SetBackground( aBackgroundColor );
+ pParent->SetBackground( aBackgroundColor );
+}
+
+TextWindow::~TextWindow()
+{
+ delete mpExtTextView;
+ delete mpExtTextEngine;
+}
+
+void TextWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ mpExtTextView->MouseMove( rMEvt );
+ Window::MouseMove( rMEvt );
+}
+
+void TextWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ mbInMBDown = TRUE; // Dann im GetFocus nicht alles selektieren wird
+ mpExtTextView->MouseButtonDown( rMEvt );
+ Window::MouseButtonDown( rMEvt );
+ GrabFocus();
+ mbInMBDown = FALSE;
+}
+
+void TextWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ mpExtTextView->MouseButtonUp( rMEvt );
+ Window::MouseButtonUp( rMEvt );
+}
+
+void TextWindow::KeyInput( const KeyEvent& rKEvent )
+{
+ BOOL bDone = FALSE;
+ USHORT nCode = rKEvent.GetKeyCode().GetCode();
+ if ( nCode == com::sun::star::awt::Key::SELECT_ALL ||
+ ( (nCode == KEY_A) && rKEvent.GetKeyCode().IsMod1() && !rKEvent.GetKeyCode().IsMod2() )
+ )
+ {
+ mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFF, 0xFFFF ) ) );
+ bDone = TRUE;
+ }
+ else if ( (nCode == KEY_S) && rKEvent.GetKeyCode().IsShift() && rKEvent.GetKeyCode().IsMod1() )
+ {
+ if ( Edit::GetGetSpecialCharsFunction() )
+ {
+ // Damit die Selektion erhalten bleibt
+ mbActivePopup = TRUE;
+ XubString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() );
+ if ( aChars.Len() )
+ {
+ mpExtTextView->InsertText( aChars );
+ mpExtTextView->GetTextEngine()->SetModified( TRUE );
+ }
+ mbActivePopup = FALSE;
+ bDone = TRUE;
+ }
+ }
+ else if ( nCode == KEY_TAB )
+ {
+ if ( !mbIgnoreTab || rKEvent.GetKeyCode().IsMod1() )
+ bDone = mpExtTextView->KeyInput( rKEvent );
+ }
+ else
+ {
+ bDone = mpExtTextView->KeyInput( rKEvent );
+ }
+
+ if ( !bDone )
+ Window::KeyInput( rKEvent );
+}
+
+void TextWindow::Paint( const Rectangle& rRect )
+{
+ mpExtTextView->Paint( rRect );
+}
+
+void TextWindow::Resize()
+{
+}
+
+void TextWindow::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
+ {
+ PopupMenu* pPopup = Edit::CreatePopupMenu();
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_HIDEDISABLED )
+ pPopup->SetMenuFlags( MENU_FLAG_HIDEDISABLEDENTRIES );
+ if ( !mpExtTextView->HasSelection() )
+ {
+ pPopup->EnableItem( SV_MENU_EDIT_CUT, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_COPY, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_DELETE, FALSE );
+ }
+ if ( mpExtTextView->IsReadOnly() )
+ {
+ pPopup->EnableItem( SV_MENU_EDIT_CUT, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_PASTE, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_DELETE, FALSE );
+ pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, FALSE );
+ }
+ if ( !mpExtTextView->GetTextEngine()->HasUndoManager() || !mpExtTextView->GetTextEngine()->GetUndoManager().GetUndoActionCount() )
+ {
+ pPopup->EnableItem( SV_MENU_EDIT_UNDO, FALSE );
+ }
+// if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.Len() ) )
+// {
+// pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, FALSE );
+// }
+ if ( !Edit::GetGetSpecialCharsFunction() )
+ {
+ USHORT nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
+ pPopup->RemoveItem( nPos );
+ pPopup->RemoveItem( nPos-1 );
+ }
+
+ mbActivePopup = TRUE;
+ Point aPos = rCEvt.GetMousePosPixel();
+ if ( !rCEvt.IsMouseEvent() )
+ {
+ // !!! Irgendwann einmal Menu zentriert in der Selektion anzeigen !!!
+ Size aSize = GetOutputSizePixel();
+ aPos = Point( aSize.Width()/2, aSize.Height()/2 );
+ }
+// pPopup->RemoveDisabledEntries();
+ USHORT n = pPopup->Execute( this, aPos );
+ Edit::DeletePopupMenu( pPopup );
+ switch ( n )
+ {
+ case SV_MENU_EDIT_UNDO: mpExtTextView->Undo();
+ mpExtTextEngine->SetModified( TRUE );
+ mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ break;
+ case SV_MENU_EDIT_CUT: mpExtTextView->Cut();
+ mpExtTextEngine->SetModified( TRUE );
+ mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ break;
+ case SV_MENU_EDIT_COPY: mpExtTextView->Copy();
+ break;
+ case SV_MENU_EDIT_PASTE: mpExtTextView->Paste();
+ mpExtTextEngine->SetModified( TRUE );
+ mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ break;
+ case SV_MENU_EDIT_DELETE: mpExtTextView->DeleteSelected();
+ mpExtTextEngine->SetModified( TRUE );
+ mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ break;
+ case SV_MENU_EDIT_SELECTALL: mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFFFFFF, 0xFFFF ) ) );
+ break;
+ case SV_MENU_EDIT_INSERTSYMBOL:
+ {
+ XubString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() );
+ if ( aChars.Len() )
+ {
+ mpExtTextView->InsertText( aChars );
+ mpExtTextEngine->SetModified( TRUE );
+ mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ }
+ }
+ break;
+ }
+ mbActivePopup = FALSE;
+ }
+ else
+ {
+ mpExtTextView->Command( rCEvt );
+ }
+ Window::Command( rCEvt );
+}
+
+void TextWindow::GetFocus()
+{
+ Window::GetFocus();
+ if ( !mbActivePopup )
+ {
+ BOOL bGotoCursor = !mpExtTextView->IsReadOnly();
+ if ( mbFocusSelectionHide && IsReallyVisible() && !mpExtTextView->IsReadOnly()
+ && ( mbSelectOnTab &&
+ (!mbInMBDown || ( GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_FOCUS ) )) )
+ {
+ // Alles selektieren, aber nicht scrollen
+ BOOL bAutoScroll = mpExtTextView->IsAutoScroll();
+ mpExtTextView->SetAutoScroll( FALSE );
+ mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFF, 0xFFFF ) ) );
+ mpExtTextView->SetAutoScroll( bAutoScroll );
+ bGotoCursor = FALSE;
+ }
+ mpExtTextView->SetPaintSelection( TRUE );
+ mpExtTextView->ShowCursor( bGotoCursor );
+ }
+}
+
+void TextWindow::LoseFocus()
+{
+ Window::LoseFocus();
+
+ if ( mbFocusSelectionHide && !mbActivePopup )
+ mpExtTextView->SetPaintSelection( FALSE );
+}
+
+// virtual
+::css::uno::Reference< ::css::awt::XWindowPeer >
+TextWindow::GetComponentInterface(BOOL bCreate)
+{
+ ::css::uno::Reference< ::css::awt::XWindowPeer > xPeer(
+ Window::GetComponentInterface(false));
+ if (!xPeer.is() && bCreate)
+ {
+ xPeer = new ::svt::TextWindowPeer(*GetTextView(), true);
+ SetComponentInterface(xPeer);
+ }
+ return xPeer;
+}
+
+MultiLineEdit::MultiLineEdit( Window* pParent, WinBits nWinStyle )
+ : Edit( pParent, nWinStyle )
+{
+ SetType( WINDOW_MULTILINEEDIT );
+ pImpSvMEdit = new ImpSvMEdit( this, nWinStyle );
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ pUpdateDataTimer = 0;
+
+ SetCompoundControl( TRUE );
+ SetStyle( ImplInitStyle( nWinStyle ) );
+}
+
+MultiLineEdit::MultiLineEdit( Window* pParent, const ResId& rResId )
+ : Edit( pParent, rResId.SetRT( RSC_MULTILINEEDIT ) )
+{
+ SetType( WINDOW_MULTILINEEDIT );
+ WinBits nWinStyle = rResId.GetWinBits();
+ pImpSvMEdit = new ImpSvMEdit( this, nWinStyle );
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ pUpdateDataTimer = 0;
+
+ USHORT nMaxLen = Edit::GetMaxTextLen();
+ if ( nMaxLen )
+ SetMaxTextLen( nMaxLen );
+
+ SetText( Edit::GetText() );
+
+ if ( IsVisible() )
+ pImpSvMEdit->Resize();
+
+ SetCompoundControl( TRUE );
+ SetStyle( ImplInitStyle( nWinStyle ) );
+
+ // Base Edit ctor could call Show already, but that would cause problems
+ // with accessibility, as Show might (indirectly) trigger a call to virtual
+ // GetComponentInterface, which is the Edit's base version instead of the
+ // MultiLineEdit's version while in the base Edit ctor:
+ if ((GetStyle() & WB_HIDE) == 0)
+ Show();
+}
+
+MultiLineEdit::~MultiLineEdit()
+{
+ {
+ ::std::auto_ptr< ImpSvMEdit > pDelete( pImpSvMEdit );
+ pImpSvMEdit = NULL;
+ }
+ delete pUpdateDataTimer;
+}
+
+WinBits MultiLineEdit::ImplInitStyle( WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+
+ if ( !(nStyle & WB_IGNORETAB ))
+ nStyle |= WINDOW_DLGCTRL_MOD1TAB;
+
+ return nStyle;
+}
+
+
+void MultiLineEdit::ImplInitSettings( BOOL /*bFont*/, BOOL /*bForeground*/, BOOL bBackground )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ // Der Font muss immer mit manipuliert werden, weil die TextEngine
+ // sich nicht um TextColor/Background kuemmert
+
+ Color aTextColor = rStyleSettings.GetFieldTextColor();
+ if ( IsControlForeground() )
+ aTextColor = GetControlForeground();
+ if ( !IsEnabled() )
+ aTextColor = rStyleSettings.GetDisableColor();
+
+ Font aFont = rStyleSettings.GetFieldFont();
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ aFont.SetTransparent( IsPaintTransparent() );
+ SetZoomedPointFont( aFont );
+ Font TheFont = GetFont();
+ TheFont.SetColor( aTextColor );
+ if( IsPaintTransparent() )
+ TheFont.SetFillColor( Color( COL_TRANSPARENT ) );
+ else
+ TheFont.SetFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
+ pImpSvMEdit->GetTextWindow()->SetFont( TheFont );
+ pImpSvMEdit->GetTextWindow()->GetTextEngine()->SetFont( TheFont );
+ pImpSvMEdit->GetTextWindow()->SetTextColor( aTextColor );
+
+ if ( bBackground )
+ {
+ if( IsPaintTransparent() )
+ {
+ pImpSvMEdit->GetTextWindow()->SetPaintTransparent( TRUE );
+ pImpSvMEdit->GetTextWindow()->SetBackground();
+ pImpSvMEdit->GetTextWindow()->SetControlBackground();
+ SetBackground();
+ SetControlBackground();
+ }
+ else
+ {
+ if( IsControlBackground() )
+ pImpSvMEdit->GetTextWindow()->SetBackground( GetControlBackground() );
+ else
+ pImpSvMEdit->GetTextWindow()->SetBackground( rStyleSettings.GetFieldColor() );
+ // Auch am MultiLineEdit einstellen, weil die TextComponent
+ // ggf. die Scrollbars hidet.
+ SetBackground( pImpSvMEdit->GetTextWindow()->GetBackground() );
+ }
+ }
+}
+
+void MultiLineEdit::Modify()
+{
+ aModifyHdlLink.Call( this );
+
+ CallEventListeners( VCLEVENT_EDIT_MODIFY );
+
+ if ( pUpdateDataTimer )
+ pUpdateDataTimer->Start();
+}
+
+IMPL_LINK( MultiLineEdit, ImpUpdateDataHdl, Timer*, EMPTYARG )
+{
+ UpdateData();
+ return 0;
+}
+
+void MultiLineEdit::UpdateData()
+{
+ aUpdateDataHdlLink.Call( this );
+}
+
+void MultiLineEdit::SetModifyFlag()
+{
+ pImpSvMEdit->SetModified( TRUE );
+}
+
+void MultiLineEdit::ClearModifyFlag()
+{
+ pImpSvMEdit->SetModified( FALSE );
+}
+
+BOOL MultiLineEdit::IsModified() const
+{
+ return pImpSvMEdit->IsModified();
+}
+
+void MultiLineEdit::EnableUpdateData( ULONG nTimeout )
+{
+ if ( !nTimeout )
+ DisableUpdateData();
+ else
+ {
+ if ( !pUpdateDataTimer )
+ {
+ pUpdateDataTimer = new Timer;
+ pUpdateDataTimer->SetTimeoutHdl( LINK( this, MultiLineEdit, ImpUpdateDataHdl ) );
+ }
+ pUpdateDataTimer->SetTimeout( nTimeout );
+ }
+}
+
+void MultiLineEdit::SetReadOnly( BOOL bReadOnly )
+{
+ pImpSvMEdit->SetReadOnly( bReadOnly );
+ Edit::SetReadOnly( bReadOnly );
+
+ // #94921# ReadOnly can be overwritten in InitFromStyle() when WB not set.
+ WinBits nStyle = GetStyle();
+ if ( bReadOnly )
+ nStyle |= WB_READONLY;
+ else
+ nStyle &= ~WB_READONLY;
+ SetStyle( nStyle );
+}
+
+BOOL MultiLineEdit::IsReadOnly() const
+{
+ return pImpSvMEdit->IsReadOnly();
+}
+
+void MultiLineEdit::SetMaxTextLen( xub_StrLen nMaxLen )
+{
+ pImpSvMEdit->SetMaxTextLen( nMaxLen );
+}
+
+xub_StrLen MultiLineEdit::GetMaxTextLen() const
+{
+ return pImpSvMEdit->GetMaxTextLen();
+}
+
+void MultiLineEdit::ReplaceSelected( const String& rStr )
+{
+ pImpSvMEdit->InsertText( rStr );
+}
+
+void MultiLineEdit::DeleteSelected()
+{
+ pImpSvMEdit->InsertText( String() );
+}
+
+String MultiLineEdit::GetSelected() const
+{
+ return pImpSvMEdit->GetSelected();
+}
+
+String MultiLineEdit::GetSelected( LineEnd aSeparator ) const
+{
+ return pImpSvMEdit->GetSelected( aSeparator );
+}
+
+void MultiLineEdit::Cut()
+{
+ pImpSvMEdit->Cut();
+}
+
+void MultiLineEdit::Copy()
+{
+ pImpSvMEdit->Copy();
+}
+
+void MultiLineEdit::Paste()
+{
+ pImpSvMEdit->Paste();
+}
+
+void MultiLineEdit::SetText( const String& rStr )
+{
+ pImpSvMEdit->SetText( rStr );
+}
+
+String MultiLineEdit::GetText() const
+{
+ return pImpSvMEdit->GetText();
+}
+
+String MultiLineEdit::GetText( LineEnd aSeparator ) const
+{
+ return pImpSvMEdit->GetText( aSeparator );
+}
+
+String MultiLineEdit::GetTextLines() const
+{
+ return pImpSvMEdit->GetTextLines();
+}
+
+String MultiLineEdit::GetTextLines( LineEnd aSeparator ) const
+{
+ return pImpSvMEdit->GetTextLines( aSeparator );
+}
+
+void MultiLineEdit::Resize()
+{
+ pImpSvMEdit->Resize();
+}
+
+void MultiLineEdit::GetFocus()
+{
+ if ( !pImpSvMEdit ) // might be called from within the dtor, when pImpSvMEdit == NULL is a valid state
+ return;
+
+ Edit::GetFocus();
+ pImpSvMEdit->GetFocus();
+}
+
+void MultiLineEdit::SetSelection( const Selection& rSelection )
+{
+ pImpSvMEdit->SetSelection( rSelection );
+}
+
+const Selection& MultiLineEdit::GetSelection() const
+{
+ return pImpSvMEdit->GetSelection();
+}
+
+Size MultiLineEdit::CalcMinimumSize() const
+{
+ Size aSz = pImpSvMEdit->CalcMinimumSize();
+
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
+ aSz.Width() += nLeft+nRight;
+ aSz.Height() += nTop+nBottom;
+
+ return aSz;
+}
+
+Size MultiLineEdit::CalcAdjustedSize( const Size& rPrefSize ) const
+{
+ Size aSz = rPrefSize;
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
+
+ // In der Hoehe auf ganze Zeilen justieren
+
+ long nHeight = aSz.Height() - nTop - nBottom;
+ long nLineHeight = pImpSvMEdit->CalcSize( 1, 1 ).Height();
+ long nLines = nHeight / nLineHeight;
+ if ( nLines < 1 )
+ nLines = 1;
+
+ aSz.Height() = nLines * nLineHeight;
+ aSz.Height() += nTop+nBottom;
+
+ return aSz;
+}
+
+Size MultiLineEdit::CalcSize( USHORT nColumns, USHORT nLines ) const
+{
+ Size aSz = pImpSvMEdit->CalcSize( nColumns, nLines );
+
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
+ aSz.Width() += nLeft+nRight;
+ aSz.Height() += nTop+nBottom;
+ return aSz;
+}
+
+void MultiLineEdit::GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const
+{
+ pImpSvMEdit->GetMaxVisColumnsAndLines( rnCols, rnLines );
+}
+
+void MultiLineEdit::StateChanged( StateChangedType nType )
+{
+ if( nType == STATE_CHANGE_ENABLE )
+ {
+ pImpSvMEdit->Enable( IsEnabled() );
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ }
+ else if( nType == STATE_CHANGE_READONLY )
+ {
+ pImpSvMEdit->SetReadOnly( IsReadOnly() );
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ pImpSvMEdit->GetTextWindow()->SetZoom( GetZoom() );
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Resize();
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ pImpSvMEdit->InitFromStyle( GetStyle() );
+ SetStyle( ImplInitStyle( GetStyle() ) );
+ }
+ else if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ if( IsPaintTransparent() )
+ {
+ pImpSvMEdit->GetTextWindow()->SetPaintTransparent( TRUE );
+ pImpSvMEdit->GetTextWindow()->SetBackground();
+ pImpSvMEdit->GetTextWindow()->SetControlBackground();
+ SetBackground();
+ SetControlBackground();
+ }
+ }
+
+ Control::StateChanged( nType );
+}
+
+void MultiLineEdit::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Resize();
+ Invalidate();
+ }
+ else
+ Control::DataChanged( rDCEvt );
+}
+
+void MultiLineEdit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ ImplInitSettings( TRUE, TRUE, TRUE );
+
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ Font aFont = pImpSvMEdit->GetTextWindow()->GetDrawPixelFont( pDev );
+ aFont.SetTransparent( TRUE );
+ OutDevType eOutDevType = pDev->GetOutDevType();
+
+ pDev->Push();
+ pDev->SetMapMode();
+ pDev->SetFont( aFont );
+ pDev->SetTextFillColor();
+
+ // Border/Background
+ pDev->SetLineColor();
+ pDev->SetFillColor();
+ BOOL bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
+ BOOL bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
+ if ( bBorder || bBackground )
+ {
+ Rectangle aRect( aPos, aSize );
+ if ( bBorder )
+ {
+ DecorationView aDecoView( pDev );
+ aRect = aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN );
+ }
+ if ( bBackground )
+ {
+ pDev->SetFillColor( GetControlBackground() );
+ pDev->DrawRect( aRect );
+ }
+ }
+
+ // Inhalt
+ if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
+ pDev->SetTextColor( Color( COL_BLACK ) );
+ else
+ {
+ if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ pDev->SetTextColor( rStyleSettings.GetDisableColor() );
+ }
+ else
+ {
+ pDev->SetTextColor( GetTextColor() );
+ }
+ }
+
+ XubString aText = GetText();
+ Size aTextSz( pDev->GetTextWidth( aText ), pDev->GetTextHeight() );
+ ULONG nLines = (ULONG) (aSize.Height() / aTextSz.Height());
+ if ( !nLines )
+ nLines = 1;
+ aTextSz.Height() = nLines*aTextSz.Height();
+ long nOnePixel = GetDrawPixel( pDev, 1 );
+ long nOffX = 3*nOnePixel;
+ long nOffY = 2*nOnePixel;
+
+ // Clipping?
+ if ( ( nOffY < 0 ) || ( (nOffY+aTextSz.Height()) > aSize.Height() ) || ( (nOffX+aTextSz.Width()) > aSize.Width() ) )
+ {
+ Rectangle aClip( aPos, aSize );
+ if ( aTextSz.Height() > aSize.Height() )
+ aClip.Bottom() += aTextSz.Height() - aSize.Height() + 1; // Damit HP-Drucker nicht 'weg-optimieren'
+ pDev->IntersectClipRegion( aClip );
+ }
+
+ TextEngine aTE;
+ aTE.SetText( GetText() );
+ aTE.SetMaxTextWidth( aSize.Width() );
+ aTE.SetFont( aFont );
+ aTE.SetTextAlign( pImpSvMEdit->GetTextWindow()->GetTextEngine()->GetTextAlign() );
+ aTE.Draw( pDev, Point( aPos.X() + nOffX, aPos.Y() + nOffY ) );
+
+ pDev->Pop();
+}
+
+long MultiLineEdit::Notify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ nDone = pImpSvMEdit->HandleCommand( *rNEvt.GetCommandEvent() );
+ }
+ return nDone ? nDone : Edit::Notify( rNEvt );
+}
+
+long MultiLineEdit::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+
+#if (OSL_DEBUG_LEVEL > 1) && defined(DBG_UTIL)
+ if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyEvent& rKEvent = *rNEvt.GetKeyEvent();
+ if ( ( rKEvent.GetKeyCode().GetCode() == KEY_W ) && rKEvent.GetKeyCode().IsMod1() && rKEvent.GetKeyCode().IsMod2() )
+ {
+ SetRightToLeft( !IsRightToLeft() );
+ }
+ }
+#endif
+
+ if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( !GetTextView()->IsCursorEnabled() ) )
+ {
+ const KeyEvent& rKEvent = *rNEvt.GetKeyEvent();
+ if ( !rKEvent.GetKeyCode().IsShift() && ( rKEvent.GetKeyCode().GetGroup() == KEYGROUP_CURSOR ) )
+ {
+ nDone = 1;
+ TextSelection aSel = pImpSvMEdit->GetTextWindow()->GetTextView()->GetSelection();
+ if ( aSel.HasRange() )
+ {
+ aSel.GetStart() = aSel.GetEnd();
+ pImpSvMEdit->GetTextWindow()->GetTextView()->SetSelection( aSel );
+ }
+ else
+ {
+ switch ( rKEvent.GetKeyCode().GetCode() )
+ {
+ case KEY_UP:
+ {
+ if ( pImpSvMEdit->GetVScrollBar() )
+ pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_LINEUP );
+ }
+ break;
+ case KEY_DOWN:
+ {
+ if ( pImpSvMEdit->GetVScrollBar() )
+ pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_LINEDOWN );
+ }
+ break;
+ case KEY_PAGEUP :
+ {
+ if ( pImpSvMEdit->GetVScrollBar() )
+ pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_PAGEUP );
+ }
+ break;
+ case KEY_PAGEDOWN:
+ {
+ if ( pImpSvMEdit->GetVScrollBar() )
+ pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_PAGEDOWN );
+ }
+ break;
+ case KEY_LEFT:
+ {
+ if ( pImpSvMEdit->GetHScrollBar() )
+ pImpSvMEdit->GetHScrollBar()->DoScrollAction( SCROLL_LINEUP );
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ if ( pImpSvMEdit->GetHScrollBar() )
+ pImpSvMEdit->GetHScrollBar()->DoScrollAction( SCROLL_LINEDOWN );
+ }
+ break;
+ case KEY_HOME:
+ {
+ if ( rKEvent.GetKeyCode().IsMod1() )
+ pImpSvMEdit->GetTextWindow()->GetTextView()->
+ SetSelection( TextSelection( TextPaM( 0, 0 ) ) );
+ }
+ break;
+ case KEY_END:
+ {
+ if ( rKEvent.GetKeyCode().IsMod1() )
+ pImpSvMEdit->GetTextWindow()->GetTextView()->
+ SetSelection( TextSelection( TextPaM( 0xFFFF, 0xFFFF ) ) );
+ }
+ break;
+ default:
+ {
+ nDone = 0;
+ }
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Edit::PreNotify( rNEvt );
+}
+
+//
+// Internas fuer abgeleitete Klassen, z.B. TextComponent
+
+ExtTextEngine* MultiLineEdit::GetTextEngine() const
+{
+ return pImpSvMEdit->GetTextWindow()->GetTextEngine();
+}
+
+ExtTextView* MultiLineEdit::GetTextView() const
+{
+ return pImpSvMEdit->GetTextWindow()->GetTextView();
+}
+
+ScrollBar* MultiLineEdit::GetHScrollBar() const
+{
+ return pImpSvMEdit->GetHScrollBar();
+}
+
+
+ScrollBar* MultiLineEdit::GetVScrollBar() const
+{
+ return pImpSvMEdit->GetVScrollBar();
+}
+
+void MultiLineEdit::EnableFocusSelectionHide( BOOL bHide )
+{
+ pImpSvMEdit->GetTextWindow()->SetAutoFocusHide( bHide );
+}
+
+BOOL MultiLineEdit::IsFocusSelectionHideEnabled() const
+{
+ return pImpSvMEdit->GetTextWindow()->IsAutoFocusHide();
+}
+
+
+void MultiLineEdit::SetLeftMargin( USHORT n )
+{
+ if ( GetTextEngine() )
+ GetTextEngine()->SetLeftMargin( n );
+}
+
+USHORT MultiLineEdit::GetLeftMargin() const
+{
+ if ( GetTextEngine() )
+ return GetTextEngine()->GetLeftMargin();
+ else
+ return 0;
+}
+
+void MultiLineEdit::SetRightToLeft( BOOL bRightToLeft )
+{
+ if ( GetTextEngine() )
+ {
+ GetTextEngine()->SetRightToLeft( bRightToLeft );
+ GetTextView()->ShowCursor();
+ }
+}
+
+BOOL MultiLineEdit::IsRightToLeft() const
+{
+ BOOL bRightToLeft = FALSE;
+
+ if ( GetTextEngine() )
+ bRightToLeft = GetTextEngine()->IsRightToLeft();
+
+ return bRightToLeft;
+}
+
+// virtual
+::css::uno::Reference< ::css::awt::XWindowPeer >
+MultiLineEdit::GetComponentInterface(BOOL bCreate)
+{
+ ::css::uno::Reference< ::css::awt::XWindowPeer > xPeer(
+ Edit::GetComponentInterface(false));
+ if (!xPeer.is() && bCreate)
+ {
+ ::std::auto_ptr< VCLXMultiLineEdit > xEdit(new VCLXMultiLineEdit());
+ xEdit->SetWindow(this);
+ xPeer = xEdit.release();
+ SetComponentInterface(xPeer);
+ }
+ return xPeer;
+}
+/*-- 11.08.2004 11:29:23---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+void MultiLineEdit::DisableSelectionOnFocus()
+{
+ pImpSvMEdit->GetTextWindow()->DisableSelectionOnFocus();
+}
diff --git a/svtools/source/edit/svmedit2.cxx b/svtools/source/edit/svmedit2.cxx
new file mode 100644
index 000000000000..19eba618a828
--- /dev/null
+++ b/svtools/source/edit/svmedit2.cxx
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/svmedit2.hxx>
+#include <svtools/xtextedt.hxx>
+
+ExtMultiLineEdit::ExtMultiLineEdit( Window* pParent, WinBits nWinStyle ) :
+
+ MultiLineEdit( pParent, nWinStyle )
+
+{
+}
+
+ExtMultiLineEdit::ExtMultiLineEdit( Window* pParent, const ResId& rResId ) :
+
+ MultiLineEdit( pParent, rResId )
+
+{
+}
+
+ExtMultiLineEdit::~ExtMultiLineEdit()
+{
+}
+
+void ExtMultiLineEdit::InsertText( const String& rNew, BOOL )
+{
+ GetTextView()->InsertText( rNew, FALSE );
+}
+
+void ExtMultiLineEdit::SetAutoScroll( BOOL bAutoScroll )
+{
+ GetTextView()->SetAutoScroll( bAutoScroll );
+}
+
+void ExtMultiLineEdit::EnableCursor( BOOL bEnable )
+{
+ GetTextView()->EnableCursor( bEnable );
+}
+
+void ExtMultiLineEdit::SetAttrib( const TextAttrib& rAttr, ULONG nPara, USHORT nStart, USHORT nEnd )
+{
+ GetTextEngine()->SetAttrib( rAttr, nPara, nStart, nEnd );
+}
+
+void ExtMultiLineEdit::SetLeftMargin( USHORT nLeftMargin )
+{
+ GetTextEngine()->SetLeftMargin( nLeftMargin );
+}
+
+ULONG ExtMultiLineEdit::GetParagraphCount() const
+{
+ return GetTextEngine()->GetParagraphCount();
+}
+
diff --git a/svtools/source/edit/sychconv.cxx b/svtools/source/edit/sychconv.cxx
new file mode 100644
index 000000000000..3efa510bfc5a
--- /dev/null
+++ b/svtools/source/edit/sychconv.cxx
@@ -0,0 +1,103 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+#include "sychconv.hxx"
+#include <vcl/outdev.hxx>
+
+BOOL SymCharConverter::Convert( Font& rFont, UniString& rString, OutputDevice* pDev )
+{
+ // hibyte 0 = exact matching
+ // 1 = little differences,
+ // 2 = the converted character does not look like the original but got the same meaning
+ // 3 = the destination does not match looking and meaning of the original
+
+ static USHORT __READONLY_DATA aWingdingsToStarBatsTable[ 256 - 32 ] =
+ {
+ 0x0020, 0x0238, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0174, 0x02BA, 0x017B, 0x017C, 0x037C, 0x037C, 0x037C, 0x037C,
+ 0x0000, 0x0000, 0x0372, 0x0272, 0x0372, 0x0000, 0x0000, 0x0374, 0x0279, 0x0000, 0x027A, 0x0000, 0x0178, 0x0278, 0x0000, 0x0137,
+ 0x027E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017D, 0x0000, 0x0000, 0x0000, 0x0021, 0x03AC, 0x00AD, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x01C0, 0x0000, 0x0000, 0x0286, 0x0286, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0022, 0x0023, 0x0024, 0x0025,
+ 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x0133, 0x0000, 0x0000, 0x0000, 0x0000, 0x0193, 0x0194, 0x0000,
+ 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
+ 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01A5, 0x0095,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x002E, 0x0024, 0x0125, 0x0000, 0x0000, 0x0000, 0x014B, 0x024D, 0x014E, 0x014A,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x002F, 0x0000, 0x0000, 0x0000, 0x0035, 0x0000, 0x0000, 0x0000,
+ 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0031, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01B1,
+ 0x01AF, 0x01B2, 0x01B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0150, 0x0032, 0x0033, 0x0034, 0x01C8
+ };
+
+ static USHORT __READONLY_DATA aMonotypeSortsToStarBatsTable[ 256 - 32 ]=
+ {
+ 0x0020, 0x00cb, 0x00cb, 0x00cb, 0x00cb, 0x0074, 0x00ba, 0x0021, 0x00cc, 0x007b, 0x0036, 0x007d, 0x007e, 0x0037, 0x0038, 0x0038,
+ 0x0039, 0x0038, 0x0038, 0x0039, 0x003a, 0x004f, 0x0050, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0086, 0x0086, 0x0086,
+ 0x0052, 0x00cd, 0x0044, 0x0045, 0x0046, 0x0047, 0x0041, 0x0041, 0x0058, 0x0057, 0x0075, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059,
+ 0x005a, 0x004b, 0x004b, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004e, 0x004b, 0x004b, 0x00ce, 0x00ce, 0x00ce,
+ 0x00ce, 0x00ce, 0x00ce, 0x00ce, 0x00cf, 0x00cf, 0x00cf, 0x00cf, 0x00cf, 0x00cf, 0x00b9, 0x00b9, 0x003b, 0x003c, 0x003d, 0x003e,
+ 0x003f, 0x003e, 0x0040, 0x00c5, 0x00c4, 0x002b, 0x002c, 0x00d0, 0x00d1, 0x00d1, 0x00d1, 0x0091, 0x0092, 0x0093, 0x0094, 0x0000,
+ 0x00d2, 0x00d3, 0x00d2, 0x00d3, 0x00d2, 0x00d3, 0x00d2, 0x00d3, 0x00d2, 0x00d3, 0x00d2, 0x00d3, 0x00d2, 0x00d3, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x00d4, 0x00d4, 0x00d4, 0x00d6, 0x00d6, 0x00d4, 0x00d4, 0x00d5, 0x002a, 0x00d6, 0x00d7, 0x0068, 0x0069, 0x006a, 0x006b,
+ 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062,
+ 0x0063, 0x0064, 0x0065, 0x0066, 0x0030, 0x0031, 0x00d8, 0x00d9, 0x00da, 0x00bc, 0x00db, 0x00bc, 0x00bc, 0x00bc, 0x00bc, 0x0031,
+ 0x0031, 0x0031, 0x002f, 0x002f, 0x002f, 0x00be, 0x00be, 0x0031, 0x0031, 0x00af, 0x00af, 0x00af, 0x00af, 0x00af, 0x00af, 0x00af,
+ 0x0000, 0x00af, 0x0035, 0x00dc, 0x00da, 0x00dc, 0x00db, 0x00da, 0x00dc, 0x00db, 0x00dc, 0x00dc, 0x00dc, 0x00dc, 0x00af, 0x0000
+ };
+
+ const USHORT* pTransTable = NULL;
+
+ BOOL bIsAvailable = ( pDev ) ? pDev->IsFontAvailable( rFont.GetName() ) : FALSE;
+ if ( !bIsAvailable )
+ {
+ if ( rFont.GetName().CompareToAscii( RTL_CONSTASCII_STRINGPARAM( "Wingdings" ) ) == COMPARE_EQUAL )
+ pTransTable = &aWingdingsToStarBatsTable[ 0 ];
+ else if ( rFont.GetName().CompareToAscii( RTL_CONSTASCII_STRINGPARAM( "Monotype Sorts" ) ) == COMPARE_EQUAL )
+ pTransTable = &aMonotypeSortsToStarBatsTable[ 0 ];
+ }
+ if ( pTransTable )
+ {
+ sal_Unicode c;
+ for ( UINT16 i = rString.Len(); i--; )
+ {
+ c = rString.GetChar( i );
+ c -= 32;
+ c = ( ((UINT16)c) >= 224 ) ? 0 : (sal_Unicode) pTransTable[ c ];
+ if ( !c ) // if character is out of range or not matching
+ c = 0xA5; // we will default a StarBats-Bullet
+ rString.SetChar( i, c );
+ }
+ rFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
+ rFont.SetName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "StarBats" ) ) );
+ return TRUE;
+ }
+ else return FALSE;
+};
diff --git a/svtools/source/edit/syntaxhighlight.cxx b/svtools/source/edit/syntaxhighlight.cxx
new file mode 100644
index 000000000000..5729eb712bfe
--- /dev/null
+++ b/svtools/source/edit/syntaxhighlight.cxx
@@ -0,0 +1,909 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/syntaxhighlight.hxx>
+
+#include <unotools/charclass.hxx>
+#include <tools/debug.hxx>
+
+
+SV_IMPL_VARARR(HighlightPortions, HighlightPortion)
+
+
+// ##########################################################################
+// ATTENTION: all these words needs to be in small caps
+// ##########################################################################
+static const char* strListBasicKeyWords[] = {
+ "access",
+ "alias",
+ "and",
+ "any",
+ "append",
+ "as",
+ "base",
+ "binary",
+ "boolean",
+ "byref",
+ "byte",
+ "byval",
+ "call",
+ "case",
+ "cdecl",
+ "classmodule",
+ "close",
+ "compare",
+ "compatible",
+ "const",
+ "currency",
+ "date",
+ "declare",
+ "defbool",
+ "defcur",
+ "defdate",
+ "defdbl",
+ "deferr",
+ "defint",
+ "deflng",
+ "defobj",
+ "defsng",
+ "defstr",
+ "defvar",
+ "dim",
+ "do",
+ "double",
+ "each",
+ "else",
+ "elseif",
+ "end",
+ "end enum",
+ "end function",
+ "end if",
+ "end select",
+ "end sub",
+ "end type",
+ "endif",
+ "enum",
+ "eqv",
+ "erase",
+ "error",
+ "exit",
+ "explicit",
+ "for",
+ "function",
+ "get",
+ "global",
+ "gosub",
+ "goto",
+ "if",
+ "imp",
+ "implements",
+ "in",
+ "input",
+ "integer",
+ "is",
+ "let",
+ "lib",
+ "like",
+ "line",
+ "line input",
+ "local",
+ "lock",
+ "long",
+ "loop",
+ "lprint",
+ "lset",
+ "mod",
+ "name",
+ "new",
+ "next",
+ "not",
+ "object",
+ "on",
+ "open",
+ "option",
+ "optional",
+ "or",
+ "output",
+ "preserve",
+ "print",
+ "private",
+ "property",
+ "public",
+ "random",
+ "read",
+ "redim",
+ "rem",
+ "resume",
+ "return",
+ "rset",
+ "select",
+ "set",
+ "shared",
+ "single",
+ "static",
+ "step",
+ "stop",
+ "string",
+ "sub",
+ "system",
+ "text",
+ "then",
+ "to",
+ "type",
+ "typeof",
+ "until",
+ "variant",
+ "wend",
+ "while",
+ "with",
+ "write",
+ "xor"
+};
+
+
+static const char* strListSqlKeyWords[] = {
+ "all",
+ "and",
+ "any",
+ "as",
+ "asc",
+ "avg",
+ "between",
+ "by",
+ "cast",
+ "corresponding",
+ "count",
+ "create",
+ "cross",
+ "delete",
+ "desc",
+ "distinct",
+ "drop",
+ "escape",
+ "except",
+ "exists",
+ "false",
+ "from",
+ "full",
+ "global",
+ "group",
+ "having",
+ "in",
+ "inner",
+ "insert",
+ "intersect",
+ "into",
+ "is",
+ "join",
+ "left",
+ "like",
+ "local",
+ "match",
+ "max",
+ "min",
+ "natural",
+ "not",
+ "null",
+ "on",
+ "or",
+ "order",
+ "outer",
+ "right",
+ "select",
+ "set",
+ "some",
+ "sum",
+ "table",
+ "temporary",
+ "true",
+ "union",
+ "unique",
+ "unknown",
+ "update",
+ "using",
+ "values",
+ "where"
+};
+
+
+extern "C" int CDECL compare_strings( const void *arg1, const void *arg2 )
+{
+ return strcmp( (char *)arg1, *(char **)arg2 );
+}
+
+
+class LetterTable
+{
+ bool IsLetterTab[256];
+
+public:
+ LetterTable( void );
+
+ inline bool isLetter( sal_Unicode c )
+ {
+ bool bRet = (c < 256) ? IsLetterTab[c] : isLetterUnicode( c );
+ return bRet;
+ }
+ bool isLetterUnicode( sal_Unicode c );
+};
+
+class BasicSimpleCharClass
+{
+ static LetterTable aLetterTable;
+
+public:
+ static BOOL isAlpha( sal_Unicode c, bool bCompatible )
+ {
+ BOOL bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+ || (bCompatible && aLetterTable.isLetter( c ));
+ return bRet;
+ }
+
+ static BOOL isDigit( sal_Unicode c )
+ {
+ BOOL bRet = (c >= '0' && c <= '9');
+ return bRet;
+ }
+
+ static BOOL isAlphaNumeric( sal_Unicode c, bool bCompatible )
+ {
+ BOOL bRet = isDigit( c ) || isAlpha( c, bCompatible );
+ return bRet;
+ }
+};
+
+LetterTable BasicSimpleCharClass::aLetterTable;
+
+LetterTable::LetterTable( void )
+{
+ for( int i = 0 ; i < 256 ; ++i )
+ IsLetterTab[i] = false;
+
+ IsLetterTab[0xC0] = true; // À , CAPITAL LETTER A WITH GRAVE ACCENT
+ IsLetterTab[0xC1] = true; // Á , CAPITAL LETTER A WITH ACUTE ACCENT
+ IsLetterTab[0xC2] = true; // Â , CAPITAL LETTER A WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xC3] = true; // Ã , CAPITAL LETTER A WITH TILDE
+ IsLetterTab[0xC4] = true; // Ä , CAPITAL LETTER A WITH DIAERESIS
+ IsLetterTab[0xC5] = true; // Å , CAPITAL LETTER A WITH RING ABOVE
+ IsLetterTab[0xC6] = true; // Æ , CAPITAL LIGATURE AE
+ IsLetterTab[0xC7] = true; // Ç , CAPITAL LETTER C WITH CEDILLA
+ IsLetterTab[0xC8] = true; // È , CAPITAL LETTER E WITH GRAVE ACCENT
+ IsLetterTab[0xC9] = true; // É , CAPITAL LETTER E WITH ACUTE ACCENT
+ IsLetterTab[0xCA] = true; // Ê , CAPITAL LETTER E WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xCB] = true; // Ë , CAPITAL LETTER E WITH DIAERESIS
+ IsLetterTab[0xCC] = true; // Ì , CAPITAL LETTER I WITH GRAVE ACCENT
+ IsLetterTab[0xCD] = true; // Í , CAPITAL LETTER I WITH ACUTE ACCENT
+ IsLetterTab[0xCE] = true; // Î , CAPITAL LETTER I WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xCF] = true; // Ï , CAPITAL LETTER I WITH DIAERESIS
+ IsLetterTab[0xD0] = true; // Ð , CAPITAL LETTER ETH
+ IsLetterTab[0xD1] = true; // Ñ , CAPITAL LETTER N WITH TILDE
+ IsLetterTab[0xD2] = true; // Ò , CAPITAL LETTER O WITH GRAVE ACCENT
+ IsLetterTab[0xD3] = true; // Ó , CAPITAL LETTER O WITH ACUTE ACCENT
+ IsLetterTab[0xD4] = true; // Ô , CAPITAL LETTER O WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xD5] = true; // Õ , CAPITAL LETTER O WITH TILDE
+ IsLetterTab[0xD6] = true; // Ö , CAPITAL LETTER O WITH DIAERESIS
+ IsLetterTab[0xD8] = true; // Ø , CAPITAL LETTER O WITH STROKE
+ IsLetterTab[0xD9] = true; // Ù , CAPITAL LETTER U WITH GRAVE ACCENT
+ IsLetterTab[0xDA] = true; // Ú , CAPITAL LETTER U WITH ACUTE ACCENT
+ IsLetterTab[0xDB] = true; // Û , CAPITAL LETTER U WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xDC] = true; // Ü , CAPITAL LETTER U WITH DIAERESIS
+ IsLetterTab[0xDD] = true; // Ý , CAPITAL LETTER Y WITH ACUTE ACCENT
+ IsLetterTab[0xDE] = true; // Þ , CAPITAL LETTER THORN
+ IsLetterTab[0xDF] = true; // ß , SMALL LETTER SHARP S
+ IsLetterTab[0xE0] = true; // à , SMALL LETTER A WITH GRAVE ACCENT
+ IsLetterTab[0xE1] = true; // á , SMALL LETTER A WITH ACUTE ACCENT
+ IsLetterTab[0xE2] = true; // â , SMALL LETTER A WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xE3] = true; // ã , SMALL LETTER A WITH TILDE
+ IsLetterTab[0xE4] = true; // ä , SMALL LETTER A WITH DIAERESIS
+ IsLetterTab[0xE5] = true; // å , SMALL LETTER A WITH RING ABOVE
+ IsLetterTab[0xE6] = true; // æ , SMALL LIGATURE AE
+ IsLetterTab[0xE7] = true; // ç , SMALL LETTER C WITH CEDILLA
+ IsLetterTab[0xE8] = true; // è , SMALL LETTER E WITH GRAVE ACCENT
+ IsLetterTab[0xE9] = true; // é , SMALL LETTER E WITH ACUTE ACCENT
+ IsLetterTab[0xEA] = true; // ê , SMALL LETTER E WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xEB] = true; // ë , SMALL LETTER E WITH DIAERESIS
+ IsLetterTab[0xEC] = true; // ì , SMALL LETTER I WITH GRAVE ACCENT
+ IsLetterTab[0xED] = true; // í , SMALL LETTER I WITH ACUTE ACCENT
+ IsLetterTab[0xEE] = true; // î , SMALL LETTER I WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xEF] = true; // ï , SMALL LETTER I WITH DIAERESIS
+ IsLetterTab[0xF0] = true; // ð , SMALL LETTER ETH
+ IsLetterTab[0xF1] = true; // ñ , SMALL LETTER N WITH TILDE
+ IsLetterTab[0xF2] = true; // ò , SMALL LETTER O WITH GRAVE ACCENT
+ IsLetterTab[0xF3] = true; // ó , SMALL LETTER O WITH ACUTE ACCENT
+ IsLetterTab[0xF4] = true; // ô , SMALL LETTER O WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xF5] = true; // õ , SMALL LETTER O WITH TILDE
+ IsLetterTab[0xF6] = true; // ö , SMALL LETTER O WITH DIAERESIS
+ IsLetterTab[0xF8] = true; // ø , SMALL LETTER O WITH OBLIQUE BAR
+ IsLetterTab[0xF9] = true; // ù , SMALL LETTER U WITH GRAVE ACCENT
+ IsLetterTab[0xFA] = true; // ú , SMALL LETTER U WITH ACUTE ACCENT
+ IsLetterTab[0xFB] = true; // û , SMALL LETTER U WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xFC] = true; // ü , SMALL LETTER U WITH DIAERESIS
+ IsLetterTab[0xFD] = true; // ý , SMALL LETTER Y WITH ACUTE ACCENT
+ IsLetterTab[0xFE] = true; // þ , SMALL LETTER THORN
+ IsLetterTab[0xFF] = true; // ÿ , SMALL LETTER Y WITH DIAERESIS
+}
+
+bool LetterTable::isLetterUnicode( sal_Unicode c )
+{
+ static CharClass* pCharClass = NULL;
+ if( pCharClass == NULL )
+ pCharClass = new CharClass( Application::GetSettings().GetLocale() );
+ String aStr( c );
+ bool bRet = pCharClass->isLetter( aStr, 0 );
+ return bRet;
+}
+
+// Hilfsfunktion: Zeichen-Flag Testen
+BOOL SimpleTokenizer_Impl::testCharFlags( sal_Unicode c, USHORT nTestFlags )
+{
+ bool bRet = false;
+ if( c != 0 && c <= 255 )
+ {
+ bRet = ( (aCharTypeTab[c] & nTestFlags) != 0 );
+ }
+ else if( c > 255 )
+ {
+ bRet = (( CHAR_START_IDENTIFIER | CHAR_IN_IDENTIFIER ) & nTestFlags) != 0
+ ? BasicSimpleCharClass::isAlpha( c, true ) : false;
+ }
+ return bRet;
+}
+
+void SimpleTokenizer_Impl::setKeyWords( const char** ppKeyWords, UINT16 nCount )
+{
+ ppListKeyWords = ppKeyWords;
+ nKeyWordCount = nCount;
+}
+
+// Neues Token holen
+BOOL SimpleTokenizer_Impl::getNextToken( /*out*/TokenTypes& reType,
+ /*out*/const sal_Unicode*& rpStartPos, /*out*/const sal_Unicode*& rpEndPos )
+{
+ reType = TT_UNKNOWN;
+
+ // Position merken
+ rpStartPos = mpActualPos;
+
+ // Zeichen untersuchen
+ sal_Unicode c = peekChar();
+ if( c == CHAR_EOF )
+ return FALSE;
+
+ // Zeichen lesen
+ getChar();
+
+ //*** Alle Moeglichkeiten durchgehen ***
+ // Space?
+ if ( (testCharFlags( c, CHAR_SPACE ) == TRUE) )
+ {
+ while( testCharFlags( peekChar(), CHAR_SPACE ) == TRUE )
+ getChar();
+
+ reType = TT_WHITESPACE;
+ }
+
+ // Identifier?
+ else if ( (testCharFlags( c, CHAR_START_IDENTIFIER ) == TRUE) )
+ {
+ BOOL bIdentifierChar;
+ do
+ {
+ // Naechstes Zeichen holen
+ c = peekChar();
+ bIdentifierChar = testCharFlags( c, CHAR_IN_IDENTIFIER );
+ if( bIdentifierChar )
+ getChar();
+ }
+ while( bIdentifierChar );
+
+ reType = TT_IDENTIFIER;
+
+ // Schluesselwort-Tabelle
+ if (ppListKeyWords != NULL)
+ {
+ int nCount = mpActualPos - rpStartPos;
+
+ // No keyword if string contains char > 255
+ bool bCanBeKeyword = true;
+ for( int i = 0 ; i < nCount ; i++ )
+ {
+ if( rpStartPos[i] > 255 )
+ {
+ bCanBeKeyword = false;
+ break;
+ }
+ }
+
+ if( bCanBeKeyword )
+ {
+ String aKWString(rpStartPos, sal::static_int_cast< xub_StrLen >(nCount) );
+ ByteString aByteStr( aKWString, RTL_TEXTENCODING_ASCII_US );
+ aByteStr.ToLowerAscii();
+ if ( bsearch( aByteStr.GetBuffer(), ppListKeyWords, nKeyWordCount, sizeof( char* ),
+ compare_strings ) )
+ {
+ reType = TT_KEYWORDS;
+
+ if ( aByteStr.Equals( "rem" ) )
+ {
+ // Alle Zeichen bis Zeilen-Ende oder EOF entfernen
+ sal_Unicode cPeek = peekChar();
+ while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE )
+ {
+ c = getChar();
+ cPeek = peekChar();
+ }
+
+ reType = TT_COMMENT;
+ }
+ }
+ }
+ }
+ }
+
+ // Operator?
+ // only for BASIC '\'' should be a comment, otherwise it is a normal string and handled there
+ else if ( ( testCharFlags( c, CHAR_OPERATOR ) == TRUE ) || ( (c == '\'') && (aLanguage==HIGHLIGHT_BASIC)) )
+ {
+ // paramters for SQL view
+ if ( (c==':') || (c=='?'))
+ {
+ if (c!='?')
+ {
+ BOOL bIdentifierChar;
+ do
+ {
+ // Naechstes Zeichen holen
+ c = peekChar();
+ bIdentifierChar = BasicSimpleCharClass::isAlpha( c, true );
+ if( bIdentifierChar )
+ getChar();
+ }
+ while( bIdentifierChar );
+ }
+ reType = TT_PARAMETER;
+ }
+ else if ((c=='-'))
+ {
+ sal_Unicode cPeekNext = peekChar();
+ if (cPeekNext=='-')
+ {
+ // Alle Zeichen bis Zeilen-Ende oder EOF entfernen
+ while( cPeekNext != CHAR_EOF && testCharFlags( cPeekNext, CHAR_EOL ) == FALSE )
+ {
+ getChar();
+ cPeekNext = peekChar();
+ }
+ reType = TT_COMMENT;
+ }
+ }
+ else if (c=='/')
+ {
+ sal_Unicode cPeekNext = peekChar();
+ if (cPeekNext=='/')
+ {
+ // Alle Zeichen bis Zeilen-Ende oder EOF entfernen
+ while( cPeekNext != CHAR_EOF && testCharFlags( cPeekNext, CHAR_EOL ) == FALSE )
+ {
+ getChar();
+ cPeekNext = peekChar();
+ }
+ reType = TT_COMMENT;
+ }
+ }
+ else
+ {
+ // Kommentar ?
+ if ( c == '\'' )
+ {
+ c = getChar(); // '/' entfernen
+
+ // Alle Zeichen bis Zeilen-Ende oder EOF entfernen
+ sal_Unicode cPeek = peekChar();
+ while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE )
+ {
+ getChar();
+ cPeek = peekChar();
+ }
+
+ reType = TT_COMMENT;
+ }
+
+ // Echter Operator, kann hier einfach behandelt werden,
+ // da nicht der wirkliche Operator, wie z.B. += interessiert,
+ // sondern nur die Tatsache, dass es sich um einen handelt.
+ if( reType != TT_COMMENT )
+ {
+ reType = TT_OPERATOR;
+ }
+
+ }
+ }
+
+ // Objekt-Trenner? Muss vor Number abgehandelt werden
+ else if( c == '.' && ( peekChar() < '0' || peekChar() > '9' ) )
+ {
+ reType = TT_OPERATOR;
+ }
+
+ // Zahl?
+ else if( testCharFlags( c, CHAR_START_NUMBER ) == TRUE )
+ {
+ reType = TT_NUMBER;
+
+ // Zahlensystem, 10 = normal, wird bei Oct/Hex geaendert
+ int nRadix = 10;
+
+ // Ist es eine Hex- oder Oct-Zahl?
+ if( c == '&' )
+ {
+ // Octal?
+ if( peekChar() == 'o' || peekChar() == 'O' )
+ {
+ // o entfernen
+ getChar();
+ nRadix = 8; // Octal-Basis
+
+ // Alle Ziffern einlesen
+ while( testCharFlags( peekChar(), CHAR_IN_OCT_NUMBER ) )
+ c = getChar();
+ }
+ // Hex?
+ else if( peekChar() == 'h' || peekChar() == 'H' )
+ {
+ // x entfernen
+ getChar();
+ nRadix = 16; // Hex-Basis
+
+ // Alle Ziffern einlesen und puffern
+ while( testCharFlags( peekChar(), CHAR_IN_HEX_NUMBER ) )
+ c = getChar();
+ }
+ else
+ {
+ reType = TT_OPERATOR;
+ }
+ }
+
+ // Wenn nicht Oct oder Hex als double ansehen
+ if( reType == TT_NUMBER && nRadix == 10 )
+ {
+ // Flag, ob das letzte Zeichen ein Exponent war
+ BOOL bAfterExpChar = FALSE;
+
+ // Alle Ziffern einlesen
+ while( testCharFlags( peekChar(), CHAR_IN_NUMBER ) ||
+ (bAfterExpChar && peekChar() == '+' ) ||
+ (bAfterExpChar && peekChar() == '-' ) )
+ // Nach Exponent auch +/- OK
+ {
+ c = getChar(); // Zeichen lesen
+ bAfterExpChar = ( c == 'e' || c == 'E' );
+ }
+ }
+
+ // reType = TT_NUMBER;
+ }
+
+ // String?
+ else if( testCharFlags( c, CHAR_START_STRING ) == TRUE )
+ {
+ // Merken, welches Zeichen den String eroeffnet hat
+ sal_Unicode cEndString = c;
+ if( c == '[' )
+ cEndString = ']';
+
+ // Alle Ziffern einlesen und puffern
+ while( peekChar() != cEndString )
+ {
+ // #58846 EOF vor getChar() abfangen, damit EOF micht verloren geht
+ if( peekChar() == CHAR_EOF )
+ {
+ // ERROR: unterminated string literal
+ reType = TT_ERROR;
+ break;
+ }
+ c = getChar();
+ if( testCharFlags( c, CHAR_EOL ) == TRUE )
+ {
+ // ERROR: unterminated string literal
+ reType = TT_ERROR;
+ break;
+ }
+ }
+
+ // Zeichen lesen
+ if( reType != TT_ERROR )
+ {
+ getChar();
+ if( cEndString == ']' )
+ reType = TT_IDENTIFIER;
+ else
+ reType = TT_STRING;
+ }
+ }
+
+ // Zeilenende?
+ else if( testCharFlags( c, CHAR_EOL ) == TRUE )
+ {
+ // Falls ein weiteres anderes EOL-Char folgt, weg damit
+ sal_Unicode cNext = peekChar();
+ if( cNext != c && testCharFlags( cNext, CHAR_EOL ) == TRUE )
+ getChar();
+
+ // Positions-Daten auf Zeilen-Beginn setzen
+ nCol = 0;
+ nLine++;
+
+ reType = TT_EOL;
+ }
+
+ // Alles andere bleibt TT_UNKNOWN
+
+
+ // End-Position eintragen
+ rpEndPos = mpActualPos;
+ return TRUE;
+}
+
+String SimpleTokenizer_Impl::getTokStr
+ ( /*out*/const sal_Unicode* pStartPos, /*out*/const sal_Unicode* pEndPos )
+{
+ return String( pStartPos, (USHORT)( pEndPos - pStartPos ) );
+}
+
+#ifdef DBG_UTIL
+// TEST: Token ausgeben
+String SimpleTokenizer_Impl::getFullTokenStr( /*out*/TokenTypes eType,
+ /*out*/const sal_Unicode* pStartPos, /*out*/const sal_Unicode* pEndPos )
+{
+ String aOut;
+ switch( eType )
+ {
+ case TT_UNKNOWN: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_UNKNOWN:") ); break;
+ case TT_IDENTIFIER: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_IDENTIFIER:") ); break;
+ case TT_WHITESPACE: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_WHITESPACE:") ); break;
+ case TT_NUMBER: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_NUMBER:") ); break;
+ case TT_STRING: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_STRING:") ); break;
+ case TT_EOL: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_EOL:") ); break;
+ case TT_COMMENT: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_COMMENT:") ); break;
+ case TT_ERROR: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_ERROR:") ); break;
+ case TT_OPERATOR: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_OPERATOR:") ); break;
+ case TT_KEYWORDS: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_KEYWORD:") ); break;
+ case TT_PARAMETER: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_PARAMETER:") ); break;
+ }
+ if( eType != TT_EOL )
+ {
+ aOut += String( pStartPos, (USHORT)( pEndPos - pStartPos ) );
+ }
+ aOut += String( RTL_CONSTASCII_USTRINGPARAM("\n") );
+ return aOut;
+}
+#endif
+
+SimpleTokenizer_Impl::SimpleTokenizer_Impl( HighlighterLanguage aLang ): aLanguage(aLang)
+{
+ memset( aCharTypeTab, 0, sizeof( aCharTypeTab ) );
+
+ // Zeichen-Tabelle fuellen
+ USHORT i;
+
+ // Zulaessige Zeichen fuer Identifier
+ USHORT nHelpMask = (USHORT)( CHAR_START_IDENTIFIER | CHAR_IN_IDENTIFIER );
+ for( i = 'a' ; i <= 'z' ; i++ )
+ aCharTypeTab[i] |= nHelpMask;
+ for( i = 'A' ; i <= 'Z' ; i++ )
+ aCharTypeTab[i] |= nHelpMask;
+ // '_' extra eintragen
+ aCharTypeTab[(int)'_'] |= nHelpMask;
+ // AB 23.6.97: '$' ist auch erlaubt
+ aCharTypeTab[(int)'$'] |= nHelpMask;
+
+ // Ziffern (Identifier und Number ist moeglich)
+ nHelpMask = (USHORT)( CHAR_IN_IDENTIFIER | CHAR_START_NUMBER |
+ CHAR_IN_NUMBER | CHAR_IN_HEX_NUMBER );
+ for( i = '0' ; i <= '9' ; i++ )
+ aCharTypeTab[i] |= nHelpMask;
+
+ // e und E sowie . von Hand ergaenzen
+ aCharTypeTab[(int)'e'] |= CHAR_IN_NUMBER;
+ aCharTypeTab[(int)'E'] |= CHAR_IN_NUMBER;
+ aCharTypeTab[(int)'.'] |= (USHORT)( CHAR_IN_NUMBER | CHAR_START_NUMBER );
+ aCharTypeTab[(int)'&'] |= CHAR_START_NUMBER;
+
+ // Hex-Ziffern
+ for( i = 'a' ; i <= 'f' ; i++ )
+ aCharTypeTab[i] |= CHAR_IN_HEX_NUMBER;
+ for( i = 'A' ; i <= 'F' ; i++ )
+ aCharTypeTab[i] |= CHAR_IN_HEX_NUMBER;
+
+ // Oct-Ziffern
+ for( i = '0' ; i <= '7' ; i++ )
+ aCharTypeTab[i] |= CHAR_IN_OCT_NUMBER;
+
+ // String-Beginn/End-Zeichen
+ aCharTypeTab[(int)'\''] |= CHAR_START_STRING;
+ aCharTypeTab[(int)'\"'] |= CHAR_START_STRING;
+ aCharTypeTab[(int)'['] |= CHAR_START_STRING;
+ aCharTypeTab[(int)'`'] |= CHAR_START_STRING;
+
+ // Operator-Zeichen
+ aCharTypeTab[(int)'!'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'%'] |= CHAR_OPERATOR;
+ // aCharTypeTab[(int)'&'] |= CHAR_OPERATOR; Removed because of #i14140
+ aCharTypeTab[(int)'('] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)')'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'*'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'+'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)','] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'-'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'/'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)':'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'<'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'='] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'>'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'?'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'^'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'|'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'~'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'{'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)'}'] |= CHAR_OPERATOR;
+ // aCharTypeTab[(int)'['] |= CHAR_OPERATOR; Removed because of #i17826
+ aCharTypeTab[(int)']'] |= CHAR_OPERATOR;
+ aCharTypeTab[(int)';'] |= CHAR_OPERATOR;
+
+ // Space
+ aCharTypeTab[(int)' ' ] |= CHAR_SPACE;
+ aCharTypeTab[(int)'\t'] |= CHAR_SPACE;
+
+ // Zeilen-Ende-Zeichen
+ aCharTypeTab[(int)'\r'] |= CHAR_EOL;
+ aCharTypeTab[(int)'\n'] |= CHAR_EOL;
+
+ ppListKeyWords = NULL;
+}
+
+SimpleTokenizer_Impl::~SimpleTokenizer_Impl( void )
+{
+}
+
+SimpleTokenizer_Impl* getSimpleTokenizer( void )
+{
+ static SimpleTokenizer_Impl* pSimpleTokenizer = NULL;
+ if( !pSimpleTokenizer )
+ pSimpleTokenizer = new SimpleTokenizer_Impl();
+ return pSimpleTokenizer;
+}
+
+// Heraussuchen der jeweils naechsten Funktion aus einem JavaScript-Modul
+UINT16 SimpleTokenizer_Impl::parseLine( UINT32 nParseLine, const String* aSource )
+{
+ // Position auf den Anfang des Source-Strings setzen
+ mpStringBegin = mpActualPos = aSource->GetBuffer();
+
+ // Zeile und Spalte initialisieren
+ nLine = nParseLine;
+ nCol = 0L;
+
+ // Variablen fuer die Out-Parameter
+ TokenTypes eType;
+ const sal_Unicode* pStartPos;
+ const sal_Unicode* pEndPos;
+
+ // Schleife ueber alle Tokens
+ UINT16 nTokenCount = 0;
+ while( getNextToken( eType, pStartPos, pEndPos ) )
+ nTokenCount++;
+
+ return nTokenCount;
+}
+
+void SimpleTokenizer_Impl::getHighlightPortions( UINT32 nParseLine, const String& rLine,
+ /*out*/HighlightPortions& portions )
+{
+ // Position auf den Anfang des Source-Strings setzen
+ mpStringBegin = mpActualPos = rLine.GetBuffer();
+
+ // Zeile und Spalte initialisieren
+ nLine = nParseLine;
+ nCol = 0L;
+
+ // Variablen fuer die Out-Parameter
+ TokenTypes eType;
+ const sal_Unicode* pStartPos;
+ const sal_Unicode* pEndPos;
+
+ // Schleife ueber alle Tokens
+ while( getNextToken( eType, pStartPos, pEndPos ) )
+ {
+ HighlightPortion portion;
+
+ portion.nBegin = (UINT16)(pStartPos - mpStringBegin);
+ portion.nEnd = (UINT16)(pEndPos - mpStringBegin);
+ portion.tokenType = eType;
+
+ portions.Insert(portion, portions.Count());
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Implementierung des SyntaxHighlighter
+
+SyntaxHighlighter::SyntaxHighlighter()
+{
+ m_pSimpleTokenizer = 0;
+ m_pKeyWords = NULL;
+ m_nKeyWordCount = 0;
+}
+
+SyntaxHighlighter::~SyntaxHighlighter()
+{
+ delete m_pSimpleTokenizer;
+ delete m_pKeyWords;
+}
+
+void SyntaxHighlighter::initialize( HighlighterLanguage eLanguage_ )
+{
+ eLanguage = eLanguage_;
+ delete m_pSimpleTokenizer;
+ m_pSimpleTokenizer = new SimpleTokenizer_Impl(eLanguage);
+
+ switch (eLanguage)
+ {
+ case HIGHLIGHT_BASIC:
+ m_pSimpleTokenizer->setKeyWords( strListBasicKeyWords,
+ sizeof( strListBasicKeyWords ) / sizeof( char* ));
+ break;
+ case HIGHLIGHT_SQL:
+ m_pSimpleTokenizer->setKeyWords( strListSqlKeyWords,
+ sizeof( strListSqlKeyWords ) / sizeof( char* ));
+ break;
+ default:
+ m_pSimpleTokenizer->setKeyWords( NULL, 0 );
+ }
+}
+
+const Range SyntaxHighlighter::notifyChange( UINT32 nLine, INT32 nLineCountDifference,
+ const String* pChangedLines, UINT32 nArrayLength)
+{
+ (void)nLineCountDifference;
+
+ for( UINT32 i=0 ; i < nArrayLength ; i++ )
+ m_pSimpleTokenizer->parseLine(nLine+i, &pChangedLines[i]);
+
+ return Range( nLine, nLine + nArrayLength-1 );
+}
+
+void SyntaxHighlighter::getHighlightPortions( UINT32 nLine, const String& rLine,
+ /*out*/HighlightPortions& portions )
+{
+ m_pSimpleTokenizer->getHighlightPortions( nLine, rLine, portions );
+}
diff --git a/svtools/source/edit/textdat2.hxx b/svtools/source/edit/textdat2.hxx
new file mode 100644
index 000000000000..222e8abee5a4
--- /dev/null
+++ b/svtools/source/edit/textdat2.hxx
@@ -0,0 +1,306 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+
+#ifndef _TEXTDAT2_HXX
+#define _TEXTDAT2_HXX
+
+#include <svl/svarray.hxx>
+#include <tools/list.hxx>
+#include <vcl/seleng.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/cursor.hxx>
+
+class TextNode;
+class TextView;
+
+#define PORTIONKIND_TEXT 0
+#define PORTIONKIND_TAB 1
+
+#define DELMODE_SIMPLE 0
+#define DELMODE_RESTOFWORD 1
+#define DELMODE_RESTOFCONTENT 2
+
+#define DEL_LEFT 1
+#define DEL_RIGHT 2
+#define TRAVEL_X_DONTKNOW 0xFFFF
+#define MAXCHARSINPARA 0x3FFF-CHARPOSGROW
+
+#define LINE_SEP 0x0A
+
+
+class TETextPortion
+{
+private:
+ USHORT nLen;
+ long nWidth;
+ BYTE nKind;
+ BYTE nRightToLeft;
+
+ TETextPortion() { nLen = 0; nKind = PORTIONKIND_TEXT; nWidth = -1; nRightToLeft = 0;}
+
+public:
+ TETextPortion( USHORT nL ) {
+ nLen = nL;
+ nKind = PORTIONKIND_TEXT;
+ nWidth= -1;
+ nRightToLeft = 0;
+ }
+
+ USHORT GetLen() const { return nLen; }
+ USHORT& GetLen() { return nLen; }
+
+ long GetWidth()const { return nWidth; }
+ long& GetWidth() { return nWidth; }
+
+ BYTE GetKind() const { return nKind; }
+ BYTE& GetKind() { return nKind; }
+
+ BYTE GetRightToLeft() const { return nRightToLeft; }
+ BYTE& GetRightToLeft() { return nRightToLeft; }
+ BOOL IsRightToLeft() const { return (nRightToLeft&1); }
+
+ BOOL HasValidSize() const { return nWidth != (-1); }
+};
+
+
+
+typedef TETextPortion* TextPortionPtr;
+SV_DECL_PTRARR( TextPortionArray, TextPortionPtr, 0, 8 )
+
+class TETextPortionList : public TextPortionArray
+{
+public:
+ TETextPortionList();
+ ~TETextPortionList();
+
+ void Reset();
+ USHORT FindPortion( USHORT nCharPos, USHORT& rPortionStart, BOOL bPreferStartingPortion = FALSE );
+ USHORT GetPortionStartIndex( USHORT nPortion );
+ void DeleteFromPortion( USHORT nDelFrom );
+};
+
+struct TEWritingDirectionInfo
+{
+ BYTE nType;
+ USHORT nStartPos;
+ USHORT nEndPos;
+ TEWritingDirectionInfo( BYTE _Type, USHORT _Start, USHORT _End )
+ {
+ nType = _Type;
+ nStartPos = _Start;
+ nEndPos = _End;
+ }
+};
+
+SV_DECL_VARARR( TEWritingDirectionInfos, TEWritingDirectionInfo, 0, 4 )
+
+class TextLine
+{
+private:
+ USHORT mnStart;
+ USHORT mnEnd;
+ USHORT mnStartPortion;
+ USHORT mnEndPortion;
+
+ short mnStartX;
+
+ BOOL mbInvalid; // fuer geschickte Formatierung/Ausgabe
+
+public:
+ TextLine() {
+ mnStart = mnEnd = 0;
+ mnStartPortion = mnEndPortion = 0;
+ mnStartX = 0;
+ mbInvalid = TRUE;
+ }
+
+ BOOL IsIn( USHORT nIndex ) const
+ { return ( (nIndex >= mnStart ) && ( nIndex < mnEnd ) ); }
+
+ BOOL IsIn( USHORT nIndex, BOOL bInclEnd ) const
+ { return ( ( nIndex >= mnStart ) && ( bInclEnd ? ( nIndex <= mnEnd ) : ( nIndex < mnEnd ) ) ); }
+
+ void SetStart( USHORT n ) { mnStart = n; }
+ USHORT GetStart() const { return mnStart; }
+ USHORT& GetStart() { return mnStart; }
+
+ void SetEnd( USHORT n ) { mnEnd = n; }
+ USHORT GetEnd() const { return mnEnd; }
+ USHORT& GetEnd() { return mnEnd; }
+
+ void SetStartPortion( USHORT n ) { mnStartPortion = n; }
+ USHORT GetStartPortion() const { return mnStartPortion; }
+ USHORT& GetStartPortion() { return mnStartPortion; }
+
+ void SetEndPortion( USHORT n ) { mnEndPortion = n; }
+ USHORT GetEndPortion() const { return mnEndPortion; }
+ USHORT& GetEndPortion() { return mnEndPortion; }
+
+ USHORT GetLen() const { return mnEnd - mnStart; }
+
+ BOOL IsInvalid() const { return mbInvalid; }
+ BOOL IsValid() const { return !mbInvalid; }
+ void SetInvalid() { mbInvalid = TRUE; }
+ void SetValid() { mbInvalid = FALSE; }
+
+ BOOL IsEmpty() const { return (mnEnd > mnStart) ? FALSE : TRUE; }
+
+ short GetStartX() const { return mnStartX; }
+ void SetStartX( short n ) { mnStartX = n; }
+
+ inline BOOL operator == ( const TextLine& rLine ) const;
+ inline BOOL operator != ( const TextLine& rLine ) const;
+};
+
+typedef TextLine* TextLinePtr;
+ SV_DECL_PTRARR_DEL( TextLines, TextLinePtr, 1, 4 )
+
+inline BOOL TextLine::operator == ( const TextLine& rLine ) const
+{
+ return ( ( mnStart == rLine.mnStart ) &&
+ ( mnEnd == rLine.mnEnd ) &&
+ ( mnStartPortion == rLine.mnStartPortion ) &&
+ ( mnEndPortion == rLine.mnEndPortion ) );
+}
+
+inline BOOL TextLine::operator != ( const TextLine& rLine ) const
+{
+ return !( *this == rLine );
+}
+
+
+
+class TEParaPortion
+{
+private:
+ TextNode* mpNode;
+
+ TextLines maLines;
+ TETextPortionList maTextPortions;
+ TEWritingDirectionInfos maWritingDirectionInfos;
+
+
+ USHORT mnInvalidPosStart;
+ short mnInvalidDiff;
+
+ BOOL mbInvalid;
+ BOOL mbSimple; // nur lineares Tippen
+
+
+ TEParaPortion( const TEParaPortion& ) {;}
+
+public:
+ TEParaPortion( TextNode* pNode );
+ ~TEParaPortion();
+
+
+ BOOL IsInvalid() const { return mbInvalid; }
+ BOOL IsSimpleInvalid() const { return mbSimple; }
+ void SetNotSimpleInvalid() { mbSimple = FALSE; }
+ void SetValid() { mbInvalid = FALSE; mbSimple = TRUE;}
+
+ void MarkInvalid( USHORT nStart, short nDiff);
+ void MarkSelectionInvalid( USHORT nStart, USHORT nEnd );
+
+ USHORT GetInvalidPosStart() const { return mnInvalidPosStart; }
+ short GetInvalidDiff() const { return mnInvalidDiff; }
+
+ TextNode* GetNode() const { return mpNode; }
+ TextLines& GetLines() { return maLines; }
+ TETextPortionList& GetTextPortions() { return maTextPortions; }
+ TEWritingDirectionInfos& GetWritingDirectionInfos() { return maWritingDirectionInfos; }
+
+
+ USHORT GetLineNumber( USHORT nIndex, BOOL bInclEnd );
+ void CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine );
+};
+
+
+class TEParaPortions : public ToolsList<TEParaPortion*>
+{
+public:
+ TEParaPortions();
+ ~TEParaPortions();
+ void Reset();
+};
+
+
+class TextSelFunctionSet: public FunctionSet
+{
+private:
+ TextView* mpView;
+
+public:
+ TextSelFunctionSet( TextView* pView );
+
+ virtual void BeginDrag();
+
+ virtual void CreateAnchor();
+
+ virtual BOOL SetCursorAtPoint( const Point& rPointPixel, BOOL bDontSelectAtCursor = FALSE );
+
+ virtual BOOL IsSelectionAtPoint( const Point& rPointPixel );
+ virtual void DeselectAll();
+
+ virtual void DeselectAtPoint( const Point& );
+ virtual void DestroyAnchor();
+};
+
+
+class IdleFormatter : public Timer
+{
+private:
+ TextView* mpView;
+ USHORT mnRestarts;
+
+public:
+ IdleFormatter();
+ ~IdleFormatter();
+
+ void DoIdleFormat( TextView* pV, USHORT nMaxRestarts );
+ void ForceTimeout();
+ TextView* GetView() { return mpView; }
+};
+
+struct TextDDInfo
+{
+ Cursor maCursor;
+ TextPaM maDropPos;
+
+ BOOL mbStarterOfDD;
+ BOOL mbVisCursor;
+
+ TextDDInfo()
+ {
+ maCursor.SetStyle( CURSOR_SHADOW );
+ mbStarterOfDD = FALSE;
+ mbVisCursor = FALSE;
+ }
+};
+
+#endif // _TEXTDAT2_HXX
diff --git a/svtools/source/edit/textdata.cxx b/svtools/source/edit/textdata.cxx
new file mode 100644
index 000000000000..32bdfe40a3fb
--- /dev/null
+++ b/svtools/source/edit/textdata.cxx
@@ -0,0 +1,361 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/textdata.hxx>
+#include <textdat2.hxx>
+
+#include <tools/debug.hxx>
+
+SV_IMPL_PTRARR( TextLines, TextLinePtr );
+SV_IMPL_VARARR( TEWritingDirectionInfos, TEWritingDirectionInfo );
+
+
+ // -------------------------------------------------------------------------
+// (+) class TextSelection
+// -------------------------------------------------------------------------
+
+TextSelection::TextSelection()
+{
+}
+
+TextSelection::TextSelection( const TextPaM& rPaM ) :
+ maStartPaM( rPaM ), maEndPaM( rPaM )
+{
+}
+
+TextSelection::TextSelection( const TextPaM& rStart, const TextPaM& rEnd ) :
+ maStartPaM( rStart ), maEndPaM( rEnd )
+{
+}
+
+void TextSelection::Justify()
+{
+ if ( maEndPaM < maStartPaM )
+ {
+ TextPaM aTemp( maStartPaM );
+ maStartPaM = maEndPaM;
+ maEndPaM = aTemp;
+ }
+}
+
+
+ // -------------------------------------------------------------------------
+// (+) class TETextPortionList
+// -------------------------------------------------------------------------
+TETextPortionList::TETextPortionList()
+{
+}
+
+TETextPortionList::~TETextPortionList()
+{
+ Reset();
+}
+
+void TETextPortionList::Reset()
+{
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ delete GetObject( nPortion );
+ Remove( 0, Count() );
+}
+
+void TETextPortionList::DeleteFromPortion( USHORT nDelFrom )
+{
+ DBG_ASSERT( ( nDelFrom < Count() ) || ( (nDelFrom == 0) && (Count() == 0) ), "DeleteFromPortion: Out of range" );
+ for ( USHORT nP = nDelFrom; nP < Count(); nP++ )
+ delete GetObject( nP );
+ Remove( nDelFrom, Count()-nDelFrom );
+}
+
+USHORT TETextPortionList::FindPortion( USHORT nCharPos, USHORT& nPortionStart, BOOL bPreferStartingPortion )
+{
+ // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden
+ USHORT nTmpPos = 0;
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ {
+ TETextPortion* pPortion = GetObject( nPortion );
+ nTmpPos = nTmpPos + pPortion->GetLen();
+ if ( nTmpPos >= nCharPos )
+ {
+ // take this one if we don't prefer the starting portion, or if it's the last one
+ if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == Count() - 1 ) )
+ {
+ nPortionStart = nTmpPos - pPortion->GetLen();
+ return nPortion;
+ }
+ }
+ }
+ DBG_ERROR( "FindPortion: Nicht gefunden!" );
+ return ( Count() - 1 );
+}
+
+/*
+USHORT TETextPortionList::GetPortionStartIndex( USHORT nPortion )
+{
+ USHORT nPos = 0;
+ for ( USHORT nP = 0; nP < nPortion; nP++ )
+ {
+ TETextPortion* pPortion = GetObject( nP );
+ nPos += pPortion->GetLen();
+ }
+ return nPos;
+}
+*/
+
+
+ // -------------------------------------------------------------------------
+// (+) class TEParaPortion
+// -------------------------------------------------------------------------
+TEParaPortion::TEParaPortion( TextNode* pN )
+{
+ mpNode = pN;
+ mnInvalidPosStart = mnInvalidDiff = 0;
+ mbInvalid = TRUE;
+ mbSimple = FALSE;
+}
+
+TEParaPortion::~TEParaPortion()
+{
+}
+
+void TEParaPortion::MarkInvalid( USHORT nStart, short nDiff )
+{
+ if ( mbInvalid == FALSE )
+ {
+ mnInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
+ mnInvalidDiff = nDiff;
+ }
+ else
+ {
+ // Einfaches hintereinander tippen
+ if ( ( nDiff > 0 ) && ( mnInvalidDiff > 0 ) &&
+ ( ( mnInvalidPosStart+mnInvalidDiff ) == nStart ) )
+ {
+ mnInvalidDiff = mnInvalidDiff + nDiff;
+ }
+ // Einfaches hintereinander loeschen
+ else if ( ( nDiff < 0 ) && ( mnInvalidDiff < 0 ) && ( mnInvalidPosStart == nStart ) )
+ {
+ mnInvalidPosStart = mnInvalidPosStart + nDiff;
+ mnInvalidDiff = mnInvalidDiff + nDiff;
+ }
+ else
+ {
+ DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" );
+ mnInvalidPosStart = Min( mnInvalidPosStart, (USHORT) ( (nDiff < 0) ? nStart+nDiff : nDiff ) );
+ mnInvalidDiff = 0;
+ mbSimple = FALSE;
+ }
+ }
+
+ maWritingDirectionInfos.Remove( 0, maWritingDirectionInfos.Count() );
+
+ mbInvalid = TRUE;
+}
+
+void TEParaPortion::MarkSelectionInvalid( USHORT nStart, USHORT /*nEnd*/ )
+{
+ if ( mbInvalid == FALSE )
+ {
+ mnInvalidPosStart = nStart;
+// nInvalidPosEnd = nEnd;
+ }
+ else
+ {
+ mnInvalidPosStart = Min( mnInvalidPosStart, nStart );
+// nInvalidPosEnd = pNode->Len();
+ }
+
+ maWritingDirectionInfos.Remove( 0, maWritingDirectionInfos.Count() );
+
+ mnInvalidDiff = 0;
+ mbInvalid = TRUE;
+ mbSimple = FALSE;
+}
+
+USHORT TEParaPortion::GetLineNumber( USHORT nChar, BOOL bInclEnd )
+{
+ for ( USHORT nLine = 0; nLine < maLines.Count(); nLine++ )
+ {
+ TextLine* pLine = maLines.GetObject( nLine );
+ if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) ||
+ ( pLine->GetEnd() > nChar ) )
+ {
+ return nLine;
+ }
+ }
+
+ // Dann sollte es am Ende der letzten Zeile sein!
+ DBG_ASSERT( nChar == maLines[ maLines.Count() - 1 ]->GetEnd(), "Index voll daneben!" );
+ DBG_ASSERT( !bInclEnd, "Zeile nicht gefunden: FindLine" );
+ return ( maLines.Count() - 1 );
+}
+
+
+void TEParaPortion::CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine )
+{
+ USHORT nLines = maLines.Count();
+ DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" );
+ if ( nLastFormattedLine < ( nLines - 1 ) )
+ {
+ const TextLine* pLastFormatted = maLines[ nLastFormattedLine ];
+ const TextLine* pUnformatted = maLines[ nLastFormattedLine+1 ];
+ short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion();
+ short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd();
+ nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen!
+
+ // Die erste unformatierte muss genau eine Portion hinter der letzten der
+ // formatierten beginnen:
+ // Wenn in der geaenderten Zeile eine Portion gesplittet wurde,
+ // kann nLastEnd > nNextStart sein!
+ short nPDiff = sal::static_int_cast< short >(-( nPortionDiff-1 ));
+ short nTDiff = sal::static_int_cast< short >(-( nTextDiff-1 ));
+ if ( nPDiff || nTDiff )
+ {
+ for ( USHORT nL = nLastFormattedLine+1; nL < nLines; nL++ )
+ {
+ TextLine* pLine = maLines[ nL ];
+
+ pLine->GetStartPortion() = pLine->GetStartPortion() + nPDiff;
+ pLine->GetEndPortion() = pLine->GetEndPortion() + nPDiff;
+
+ pLine->GetStart() = pLine->GetStart() + nTDiff;
+ pLine->GetEnd() = pLine->GetEnd() + nTDiff;
+
+ pLine->SetValid();
+ }
+ }
+ }
+}
+
+ // -------------------------------------------------------------------------
+// (+) class TEParaPortions
+// -------------------------------------------------------------------------
+TEParaPortions::TEParaPortions()
+{
+}
+
+TEParaPortions::~TEParaPortions()
+{
+ Reset();
+}
+
+void TEParaPortions::Reset()
+{
+ TEParaPortions::iterator aIter( begin() );
+ while ( aIter != end() )
+ delete *aIter++;
+ clear();
+}
+
+ // -------------------------------------------------------------------------
+// (+) class IdleFormatter
+// -------------------------------------------------------------------------
+IdleFormatter::IdleFormatter()
+{
+ mpView = 0;
+ mnRestarts = 0;
+}
+
+IdleFormatter::~IdleFormatter()
+{
+ mpView = 0;
+}
+
+void IdleFormatter::DoIdleFormat( TextView* pV, USHORT nMaxRestarts )
+{
+ mpView = pV;
+
+ if ( IsActive() )
+ mnRestarts++;
+
+ if ( mnRestarts > nMaxRestarts )
+ {
+ mnRestarts = 0;
+ ((Link&)GetTimeoutHdl()).Call( this );
+ }
+ else
+ {
+ Start();
+ }
+}
+
+void IdleFormatter::ForceTimeout()
+{
+ if ( IsActive() )
+ {
+ Stop();
+ mnRestarts = 0;
+ ((Link&)GetTimeoutHdl()).Call( this );
+ }
+}
+
+TYPEINIT1( TextHint, SfxSimpleHint );
+
+TextHint::TextHint( ULONG Id ) : SfxSimpleHint( Id )
+{
+ mnValue = 0;
+}
+
+TextHint::TextHint( ULONG Id, ULONG nValue ) : SfxSimpleHint( Id )
+{
+ mnValue = nValue;
+}
+
+TEIMEInfos::TEIMEInfos( const TextPaM& rPos, const String& rOldTextAfterStartPos )
+: aOldTextAfterStartPos( rOldTextAfterStartPos )
+{
+ aPos = rPos;
+ nLen = 0;
+ bCursor = TRUE;
+ pAttribs = NULL;
+ bWasCursorOverwrite = FALSE;
+}
+
+TEIMEInfos::~TEIMEInfos()
+{
+ delete[] pAttribs;
+}
+
+void TEIMEInfos::CopyAttribs( const USHORT* pA, USHORT nL )
+{
+ nLen = nL;
+ delete pAttribs;
+ pAttribs = new USHORT[ nL ];
+ memcpy( pAttribs, pA, nL*sizeof(USHORT) );
+}
+
+void TEIMEInfos::DestroyAttribs()
+{
+ delete pAttribs;
+ pAttribs = NULL;
+ nLen = 0;
+}
+
+
diff --git a/svtools/source/edit/textdoc.cxx b/svtools/source/edit/textdoc.cxx
new file mode 100644
index 000000000000..d4470904077e
--- /dev/null
+++ b/svtools/source/edit/textdoc.cxx
@@ -0,0 +1,1047 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <textdoc.hxx>
+
+#include <stdlib.h>
+
+SV_IMPL_PTRARR( TextCharAttribs, TextCharAttribPtr );
+
+
+
+// Vergleichmethode wird von QuickSort gerufen...
+
+EXTERN_C
+#if defined( PM2 ) && (!defined( CSET ) && !defined ( MTW ) && !defined( WTC ))
+int _stdcall
+#else
+#ifdef WNT
+#if _MSC_VER >= 1200
+int __cdecl
+#else
+int _cdecl
+#endif
+#else
+int
+#endif
+#endif
+
+CompareStart( const void* pFirst, const void* pSecond )
+{
+ if ( (*((TextCharAttrib**)pFirst))->GetStart() < (*((TextCharAttrib**)pSecond))->GetStart() )
+ return (-1);
+ else if ( (*((TextCharAttrib**)pFirst))->GetStart() > (*((TextCharAttrib**)pSecond))->GetStart() )
+ return (1);
+ return 0;
+}
+
+
+ // -------------------------------------------------------------------------
+// (+) class TextCharAttrib
+// -------------------------------------------------------------------------
+TextCharAttrib::TextCharAttrib( const TextAttrib& rAttr, USHORT nStart, USHORT nEnd )
+{
+ mpAttr = rAttr.Clone();
+ mnStart = nStart,
+ mnEnd = nEnd;
+}
+
+TextCharAttrib::TextCharAttrib( const TextCharAttrib& rTextCharAttrib )
+{
+ mpAttr = rTextCharAttrib.GetAttr().Clone();
+ mnStart = rTextCharAttrib.mnStart;
+ mnEnd = rTextCharAttrib.mnEnd;
+}
+
+TextCharAttrib::~TextCharAttrib()
+{
+ delete mpAttr;
+}
+
+ // -------------------------------------------------------------------------
+// (+) class TextCharAttribList
+// -------------------------------------------------------------------------
+
+TextCharAttribList::TextCharAttribList()
+{
+ mbHasEmptyAttribs = FALSE;
+}
+
+TextCharAttribList::~TextCharAttribList()
+{
+ // PTRARR_DEL
+}
+
+void TextCharAttribList::Clear( BOOL bDestroyAttribs )
+{
+ if ( bDestroyAttribs )
+ TextCharAttribs::DeleteAndDestroy( 0, Count() );
+ else
+ TextCharAttribs::Remove( 0, Count() );
+}
+
+
+void TextCharAttribList::InsertAttrib( TextCharAttrib* pAttrib )
+{
+ if ( pAttrib->IsEmpty() )
+ mbHasEmptyAttribs = TRUE;
+
+ const USHORT nCount = Count();
+ const USHORT nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt.
+ BOOL bInserted = FALSE;
+ for ( USHORT x = 0; x < nCount; x++ )
+ {
+ TextCharAttrib* pCurAttrib = GetObject( x );
+ if ( pCurAttrib->GetStart() > nStart )
+ {
+ Insert( pAttrib, x );
+ bInserted = TRUE;
+ break;
+ }
+ }
+ if ( !bInserted )
+ Insert( pAttrib, nCount );
+}
+
+void TextCharAttribList::ResortAttribs()
+{
+ if ( Count() )
+ qsort( (void*)GetData(), Count(), sizeof( TextCharAttrib* ), CompareStart );
+}
+
+TextCharAttrib* TextCharAttribList::FindAttrib( USHORT nWhich, USHORT nPos )
+{
+ // Rueckwaerts, falls eins dort endet, das naechste startet.
+ // => Das startende gilt...
+
+ for ( USHORT nAttr = Count(); nAttr; )
+ {
+ TextCharAttrib* pAttr = GetObject( --nAttr );
+
+ if ( pAttr->GetEnd() < nPos )
+ return 0;
+
+ if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) )
+ return pAttr;
+ }
+ return NULL;
+}
+
+TextCharAttrib* TextCharAttribList::FindNextAttrib( USHORT nWhich, USHORT nFromPos, USHORT nMaxPos ) const
+{
+ DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
+ const USHORT nAttribs = Count();
+ for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetObject( nAttr );
+ if ( ( pAttr->GetStart() >= nFromPos ) &&
+ ( pAttr->GetEnd() <= nMaxPos ) &&
+ ( pAttr->Which() == nWhich ) )
+ return pAttr;
+ }
+ return NULL;
+}
+
+BOOL TextCharAttribList::HasAttrib( USHORT nWhich ) const
+{
+ for ( USHORT nAttr = Count(); nAttr; )
+ {
+ const TextCharAttrib* pAttr = GetObject( --nAttr );
+ if ( pAttr->Which() == nWhich )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL TextCharAttribList::HasBoundingAttrib( USHORT nBound )
+{
+ // Rueckwaerts, falls eins dort endet, das naechste startet.
+ // => Das startende gilt...
+ for ( USHORT nAttr = Count(); nAttr; )
+ {
+ TextCharAttrib* pAttr = GetObject( --nAttr );
+
+ if ( pAttr->GetEnd() < nBound )
+ return FALSE;
+
+ if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+TextCharAttrib* TextCharAttribList::FindEmptyAttrib( USHORT nWhich, USHORT nPos )
+{
+ if ( !mbHasEmptyAttribs )
+ return 0;
+
+ const USHORT nAttribs = Count();
+ for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetObject( nAttr );
+ if ( pAttr->GetStart() > nPos )
+ return 0;
+
+ if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) )
+ return pAttr;
+ }
+ return 0;
+}
+
+void TextCharAttribList::DeleteEmptyAttribs()
+{
+ for ( USHORT nAttr = 0; nAttr < Count(); nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetObject( nAttr );
+ if ( pAttr->IsEmpty() )
+ {
+ Remove( nAttr );
+ delete pAttr;
+ nAttr--;
+ }
+ }
+ mbHasEmptyAttribs = FALSE;
+}
+
+#ifdef DBG_UTIL
+BOOL TextCharAttribList::DbgCheckAttribs()
+{
+ BOOL bOK = TRUE;
+ for ( USHORT nAttr = 0; nAttr < Count(); nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetObject( nAttr );
+ if ( pAttr->GetStart() > pAttr->GetEnd() )
+ {
+ bOK = FALSE;
+ DBG_ERROR( "Attr verdreht" );
+ }
+ }
+ return bOK;
+}
+#endif
+
+ // -------------------------------------------------------------------------
+// (+) class TextNode
+// -------------------------------------------------------------------------
+
+TextNode::TextNode( const String& rText ) :
+ maText( rText )
+{
+}
+
+void TextNode::ExpandAttribs( USHORT nIndex, USHORT nNew )
+{
+ if ( !nNew )
+ return;
+
+ BOOL bResort = FALSE;
+ USHORT nAttribs = maCharAttribs.Count();
+ for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
+ if ( pAttrib->GetEnd() >= nIndex )
+ {
+ // Alle Attribute hinter der Einfuegeposition verschieben...
+ if ( pAttrib->GetStart() > nIndex )
+ {
+ pAttrib->MoveForward( nNew );
+ }
+ // 0: Leeres Attribut expandieren, wenn an Einfuegestelle
+ else if ( pAttrib->IsEmpty() )
+ {
+ // Index nicht pruefen, leeres durfte nur dort liegen.
+ // Wenn spaeter doch Ueberpruefung:
+ // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch!
+ // Start <= nIndex, End >= nIndex => Start=End=nIndex!
+// if ( pAttrib->GetStart() == nIndex )
+ pAttrib->Expand( nNew );
+ }
+ // 1: Attribut startet davor, geht bis Index...
+ else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen
+ {
+ // Nur expandieren, wenn kein Feature,
+ // und wenn nicht in ExcludeListe!
+ // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren
+ if ( !maCharAttribs.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
+ {
+ pAttrib->Expand( nNew );
+ }
+ else
+ bResort = TRUE;
+ }
+ // 2: Attribut startet davor, geht hinter Index...
+ else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
+ {
+ pAttrib->Expand( nNew );
+ }
+ // 3: Attribut startet auf Index...
+ else if ( pAttrib->GetStart() == nIndex )
+ {
+ if ( nIndex == 0 )
+ {
+ pAttrib->Expand( nNew );
+// bResort = TRUE; // es gibt ja keine Features mehr...
+ }
+ else
+ pAttrib->MoveForward( nNew );
+ }
+ }
+
+ DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" );
+ DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len() ), "Expand: Attrib groesser als Absatz!" );
+ DBG_ASSERT( !pAttrib->IsEmpty(), "Leeres Attribut nach ExpandAttribs?" );
+ }
+
+ if ( bResort )
+ maCharAttribs.ResortAttribs();
+
+#ifdef EDITDEBUG
+ DBG_ASSERT( CheckOrderedList( (TextCharAttribs*)&maCharAttribs ), "Expand: Start-Liste verdreht" );
+#endif
+}
+
+void TextNode::CollapsAttribs( USHORT nIndex, USHORT nDeleted )
+{
+ if ( !nDeleted )
+ return;
+
+ BOOL bResort = FALSE;
+ USHORT nEndChanges = nIndex+nDeleted;
+
+ for ( USHORT nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
+ {
+ TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
+ BOOL bDelAttr = FALSE;
+ if ( pAttrib->GetEnd() >= nIndex )
+ {
+ // Alles Attribute hinter der Einfuegeposition verschieben...
+ if ( pAttrib->GetStart() >= nEndChanges )
+ {
+ pAttrib->MoveBackward( nDeleted );
+ }
+ // 1. Innenliegende Attribute loeschen...
+ else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
+ {
+ // Spezialfall: Attrubt deckt genau den Bereich ab
+ // => als leeres Attribut behalten.
+ if ( ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
+ pAttrib->GetEnd() = nIndex; // leer
+ else
+ bDelAttr = TRUE;
+ }
+ // 2. Attribut beginnt davor, endet drinnen oder dahinter...
+ else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
+ {
+ if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen
+ pAttrib->GetEnd() = nIndex;
+ else
+ pAttrib->Collaps( nDeleted ); // endet dahinter
+ }
+ // 3. Attribut beginnt drinnen, endet dahinter...
+ else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
+ {
+ // Features duerfen nicht expandieren!
+ pAttrib->GetStart() = nEndChanges;
+ pAttrib->MoveBackward( nDeleted );
+ }
+ }
+
+ DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" );
+ DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" );
+ if ( bDelAttr /* || pAttrib->IsEmpty() */ )
+ {
+ bResort = TRUE;
+ maCharAttribs.RemoveAttrib( nAttr );
+ delete pAttrib;
+ nAttr--;
+ }
+ else if ( pAttrib->IsEmpty() )
+ maCharAttribs.HasEmptyAttribs() = TRUE;
+ }
+
+ if ( bResort )
+ maCharAttribs.ResortAttribs();
+
+#ifdef EDITDEBUG
+ DBG_ASSERT( CheckOrderedList( (TextCharAttribs)&maCharAttribs ), "Collaps: Start-Liste verdreht" );
+#endif
+}
+
+void TextNode::InsertText( USHORT nPos, const String& rText )
+{
+ maText.Insert( rText, nPos );
+ ExpandAttribs( nPos, rText.Len() );
+}
+
+void TextNode::InsertText( USHORT nPos, sal_Unicode c )
+{
+ maText.Insert( c, nPos );
+ ExpandAttribs( nPos, 1 );
+}
+
+void TextNode::RemoveText( USHORT nPos, USHORT nChars )
+{
+ maText.Erase( nPos, nChars );
+ CollapsAttribs( nPos, nChars );
+}
+
+TextNode* TextNode::Split( USHORT nPos, BOOL bKeepEndingAttribs )
+{
+ String aNewText;
+ if ( nPos < maText.Len() )
+ {
+ aNewText = maText.Copy( nPos );
+ maText.Erase( nPos );
+ }
+ TextNode* pNew = new TextNode( aNewText );
+
+ for ( USHORT nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
+ {
+ TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
+ if ( pAttrib->GetEnd() < nPos )
+ {
+ // bleiben unveraendert....
+ ;
+ }
+ else if ( pAttrib->GetEnd() == nPos )
+ {
+ // muessen als leeres Attribut kopiert werden.
+ // !FindAttrib nur sinnvoll, wenn Rueckwaerts durch Liste!
+ if ( bKeepEndingAttribs && !pNew->maCharAttribs.FindAttrib( pAttrib->Which(), 0 ) )
+ {
+ TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
+ pNewAttrib->GetStart() = 0;
+ pNewAttrib->GetEnd() = 0;
+ pNew->maCharAttribs.InsertAttrib( pNewAttrib );
+ }
+ }
+ else if ( pAttrib->IsInside( nPos ) || ( !nPos && !pAttrib->GetStart() ) )
+ {
+ // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben!
+ // muessen kopiert und geaendert werden
+ TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
+ pNewAttrib->GetStart() = 0;
+ pNewAttrib->GetEnd() = pAttrib->GetEnd()-nPos;
+ pNew->maCharAttribs.InsertAttrib( pNewAttrib );
+ // stutzen:
+ pAttrib->GetEnd() = nPos;
+ }
+ else
+ {
+ DBG_ASSERT( pAttrib->GetStart() >= nPos, "Start < nPos!" );
+ DBG_ASSERT( pAttrib->GetEnd() >= nPos, "End < nPos!" );
+ // alle dahinter verschieben in den neuen Node (this)
+ maCharAttribs.RemoveAttrib( nAttr );
+ pNew->maCharAttribs.InsertAttrib( pAttrib );
+ pAttrib->GetStart() = pAttrib->GetStart() - nPos;
+ pAttrib->GetEnd() = pAttrib->GetEnd() - nPos;
+ nAttr--;
+ }
+ }
+ return pNew;
+}
+
+void TextNode::Append( const TextNode& rNode )
+{
+ USHORT nOldLen = maText.Len();
+
+ maText += rNode.GetText();
+
+#ifdef EDITDEBUG
+ DBG_ASSERT( maCharAttribs.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" );
+#endif
+
+ const USHORT nAttribs = rNode.GetCharAttribs().Count();
+ for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttrib = rNode.GetCharAttribs().GetAttrib( nAttr );
+ BOOL bMelted = FALSE;
+ if ( pAttrib->GetStart() == 0 )
+ {
+ // Evtl koennen Attribute zusammengefasst werden:
+ USHORT nTmpAttribs = maCharAttribs.Count();
+ for ( USHORT nTmpAttr = 0; nTmpAttr < nTmpAttribs; nTmpAttr++ )
+ {
+ TextCharAttrib* pTmpAttrib = maCharAttribs.GetAttrib( nTmpAttr );
+
+ if ( pTmpAttrib->GetEnd() == nOldLen )
+ {
+ if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
+ ( pTmpAttrib->GetAttr() == pAttrib->GetAttr() ) )
+ {
+ pTmpAttrib->GetEnd() =
+ pTmpAttrib->GetEnd() + pAttrib->GetLen();
+ bMelted = TRUE;
+ break; // es kann nur eins von der Sorte an der Stelle geben
+ }
+ }
+ }
+ }
+
+ if ( !bMelted )
+ {
+ TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
+ pNewAttrib->GetStart() = pNewAttrib->GetStart() + nOldLen;
+ pNewAttrib->GetEnd() = pNewAttrib->GetEnd() + nOldLen;
+ maCharAttribs.InsertAttrib( pNewAttrib );
+ }
+ }
+
+#ifdef EDITDEBUG
+ DBG_ASSERT( maCharAttribs.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" );
+#endif
+}
+
+ // -------------------------------------------------------------------------
+// (+) class TextDoc
+// -------------------------------------------------------------------------
+
+TextDoc::TextDoc()
+{
+ mnLeftMargin = 0;
+};
+
+TextDoc::~TextDoc()
+{
+ DestroyTextNodes();
+}
+
+void TextDoc::Clear()
+{
+ DestroyTextNodes();
+}
+
+void TextDoc::DestroyTextNodes()
+{
+ for ( ULONG nNode = 0; nNode < maTextNodes.Count(); nNode++ )
+ delete maTextNodes.GetObject( nNode );
+ maTextNodes.clear();
+}
+
+String TextDoc::GetText( const sal_Unicode* pSep ) const
+{
+ ULONG nLen = GetTextLen( pSep );
+ ULONG nNodes = maTextNodes.Count();
+
+ if ( nLen > STRING_MAXLEN )
+ {
+ DBG_ERROR( "Text zu gross fuer String" );
+ return String();
+ }
+
+ String aASCIIText;
+ ULONG nLastNode = nNodes-1;
+ for ( ULONG nNode = 0; nNode < nNodes; nNode++ )
+ {
+ TextNode* pNode = maTextNodes.GetObject( nNode );
+ String aTmp( pNode->GetText() );
+ aASCIIText += aTmp;
+ if ( pSep && ( nNode != nLastNode ) )
+ aASCIIText += pSep;
+ }
+
+ return aASCIIText;
+}
+
+XubString TextDoc::GetText( ULONG nPara ) const
+{
+ XubString aText;
+ TextNode* pNode = ( nPara < maTextNodes.Count() ) ? maTextNodes.GetObject( nPara ) : 0;
+ if ( pNode )
+ aText = pNode->GetText();
+
+ return aText;
+}
+
+
+ULONG TextDoc::GetTextLen( const xub_Unicode* pSep, const TextSelection* pSel ) const
+{
+ ULONG nLen = 0;
+ ULONG nNodes = maTextNodes.Count();
+ if ( nNodes )
+ {
+ ULONG nStartNode = 0;
+ ULONG nEndNode = nNodes-1;
+ if ( pSel )
+ {
+ nStartNode = pSel->GetStart().GetPara();
+ nEndNode = pSel->GetEnd().GetPara();
+ }
+
+ for ( ULONG nNode = nStartNode; nNode <= nEndNode; nNode++ )
+ {
+ TextNode* pNode = maTextNodes.GetObject( nNode );
+
+ USHORT nS = 0;
+ ULONG nE = pNode->GetText().Len();
+ if ( pSel && ( nNode == pSel->GetStart().GetPara() ) )
+ nS = pSel->GetStart().GetIndex();
+ if ( pSel && ( nNode == pSel->GetEnd().GetPara() ) )
+ nE = pSel->GetEnd().GetIndex();
+
+ nLen += ( nE - nS );
+ }
+
+ if ( pSep )
+ nLen += (nEndNode-nStartNode) * String( pSep ).Len();
+ }
+
+ return nLen;
+}
+
+TextPaM TextDoc::InsertText( const TextPaM& rPaM, xub_Unicode c )
+{
+ DBG_ASSERT( c != 0x0A, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+ DBG_ASSERT( c != 0x0D, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ pNode->InsertText( rPaM.GetIndex(), c );
+
+ TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+1 );
+ return aPaM;
+}
+
+TextPaM TextDoc::InsertText( const TextPaM& rPaM, const XubString& rStr )
+{
+ DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+ DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ pNode->InsertText( rPaM.GetIndex(), rStr );
+
+ TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+rStr.Len() );
+ return aPaM;
+}
+
+TextPaM TextDoc::InsertParaBreak( const TextPaM& rPaM, BOOL bKeepEndingAttribs )
+{
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ TextNode* pNew = pNode->Split( rPaM.GetIndex(), bKeepEndingAttribs );
+
+ maTextNodes.Insert( pNew, rPaM.GetPara()+1 );
+
+ TextPaM aPaM( rPaM.GetPara()+1, 0 );
+ return aPaM;
+}
+
+TextPaM TextDoc::ConnectParagraphs( TextNode* pLeft, TextNode* pRight )
+{
+ USHORT nPrevLen = pLeft->GetText().Len();
+ pLeft->Append( *pRight );
+
+ // der rechte verschwindet.
+ ULONG nRight = maTextNodes.GetPos( pRight );
+ maTextNodes.Remove( nRight );
+ delete pRight;
+
+ ULONG nLeft = maTextNodes.GetPos( pLeft );
+ TextPaM aPaM( nLeft, nPrevLen );
+ return aPaM;
+}
+
+TextPaM TextDoc::RemoveChars( const TextPaM& rPaM, USHORT nChars )
+{
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ pNode->RemoveText( rPaM.GetIndex(), nChars );
+
+ return rPaM;
+}
+
+BOOL TextDoc::IsValidPaM( const TextPaM& rPaM )
+{
+ if ( rPaM.GetPara() >= maTextNodes.Count() )
+ {
+ DBG_ERROR( "PaM: Para out of range" );
+ return FALSE;
+ }
+ TextNode * pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ if ( rPaM.GetIndex() > pNode->GetText().Len() )
+ {
+ DBG_ERROR( "PaM: Index out of range" );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+
+void TextDoc::InsertAttribInSelection( TextNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem )
+{
+ DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
+ DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
+
+ // fuer Optimierung:
+ // dieses endet am Anfang der Selektion => kann erweitert werden
+ TextCharAttrib* pEndingAttrib = 0;
+ // dieses startet am Ende der Selektion => kann erweitert werden
+ TextCharAttrib* pStartingAttrib = 0;
+
+ DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
+
+ RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
+
+ if ( pStartingAttrib && pEndingAttrib &&
+ ( *(pStartingAttrib->GetItem()) == rPoolItem ) &&
+ ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
+ {
+ // wird ein groesses Attribut.
+ pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
+ pCurPool->Remove( *(pStartingAttrib->GetItem()) );
+ pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) );
+ delete pStartingAttrib;
+ }
+ else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
+ pStartingAttrib->GetStart() = nStart;
+ else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
+ pEndingAttrib->GetEnd() = nEnd;
+ else
+ InsertAttrib( rPoolItem, pNode, nStart, nEnd );
+
+ if ( pStartingAttrib )
+ pNode->GetCharAttribs().ResortAttribs();
+}
+
+BOOL TextDoc::RemoveAttribs( TextNode* pNode, USHORT nStart, USHORT nEnd, USHORT nWhich )
+{
+ TextCharAttrib* pStarting;
+ TextCharAttrib* pEnding;
+ return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich );
+}
+
+BOOL TextDoc::RemoveAttribs( TextNode* pNode, USHORT nStart, USHORT nEnd, TextCharAttrib*& rpStarting, TextCharAttrib*& rpEnding, USHORT nWhich )
+{
+ DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
+ DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
+
+ // dieses endet am Anfang der Selektion => kann erweitert werden
+ rpEnding = 0;
+ // dieses startet am Ende der Selektion => kann erweitert werden
+ rpStarting = 0;
+
+ BOOL bChanged = FALSE;
+
+ DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
+
+ // ueber die Attribute iterieren...
+ USHORT nAttr = 0;
+ TextCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
+ while ( pAttr )
+ {
+ BOOL bRemoveAttrib = FALSE;
+ if ( !nWhich || ( pAttr->Which() == nWhich ) )
+ {
+ // Attribut beginnt in Selection
+ if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
+ {
+ bChanged = TRUE;
+ if ( pAttr->GetEnd() > nEnd )
+ {
+ pAttr->GetStart() = nEnd; // dann faengt es dahinter an
+ rpStarting = pAttr;
+ break; // es kann kein weiteres Attrib hier liegen
+ }
+ else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
+ {
+ // Feature nur loeschen, wenn genau an der Stelle
+ bRemoveAttrib = TRUE;
+ }
+ }
+
+ // Attribut endet in Selection
+ else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
+ {
+ bChanged = TRUE;
+ if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
+ {
+ pAttr->GetEnd() = nStart; // dann hoert es hier auf
+ rpEnding = pAttr;
+ }
+ else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
+ {
+ // Feature nur loeschen, wenn genau an der Stelle
+ bRemoveAttrib = TRUE;
+ }
+ }
+ // Attribut ueberlappt die Selektion
+ else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
+ {
+ bChanged = TRUE;
+ if ( pAttr->GetStart() == nStart )
+ {
+ pAttr->GetStart() = nEnd;
+ rpStarting = pAttr;
+ break; // es kann weitere Attribute geben!
+ }
+ else if ( pAttr->GetEnd() == nEnd )
+ {
+ pAttr->GetEnd() = nStart;
+ rpEnding = pAttr;
+ break; // es kann weitere Attribute geben!
+ }
+ else // Attribut muss gesplittet werden...
+ {
+ USHORT nOldEnd = pAttr->GetEnd();
+ pAttr->GetEnd() = nStart;
+ rpEnding = pAttr;
+// ULONG nSavePos = pNode->GetCharAttribs().GetStartList().GetCurPos();
+ InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
+// pNode->GetCharAttribs().GetStartList().Seek( nSavePos );
+ break; // es kann weitere Attribute geben!
+ }
+ }
+ }
+ if ( bRemoveAttrib )
+ {
+ DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Loeschen und behalten des gleichen Attributs ?" );
+ pNode->GetCharAttribs().GetAttribs().Remove(nAttr);
+ pCurPool->Remove( *pAttr->GetItem() );
+ delete pAttr;
+ nAttr--;
+ }
+ nAttr++;
+ pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
+ }
+ return bChanged;
+}
+
+#pragma SEG_FUNCDEF(editdoc_3f)
+
+void TextDoc::InsertAttrib( const SfxPoolItem& rPoolItem, TextNode* pNode, USHORT nStart, USHORT nEnd )
+{
+ // Diese Methode prueft nicht mehr, ob ein entspr. Attribut
+ // schon an der Stelle existiert!
+
+ // pruefen, ob neues Attrib oder einfach nur Ende eines Attribs...
+// const SfxPoolItem& rDefItem = pNode->GetContentAttribs().GetItem( rPoolItem.Which() );
+// BOOL bCreateAttrib = ( rDefItem != rPoolItem );
+
+ // Durch den Verlust der Exclude-Liste geht es nicht mehr, dass ich
+ // kein neues Attribut benoetige und nur das alte nicht expandiere...
+// if ( !bCreateAttrib )
+ {
+ // => Wenn schon Default-Item, dann wenigstens nur dann einstellen,
+ // wenn davor wirklich ein entsprechendes Attribut.
+// if ( pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart ) )
+// bCreateAttrib = TRUE;
+ // Aber kleiner Trost:
+ // Die wenigsten schreiben, aendern das Attr, schreiben, und
+ // stellen dann wieder das Default-Attr ein.
+ }
+
+ // 22.9.95:
+ // Die Uberlegung, einfach das andere Attribut nicht zu expandieren, war
+ // sowieso falsch, da das DefAttr aus einer Vorlage kommen kann,
+ // die irgendwann verschwindet!
+// if ( bCreateAttrib )
+// {
+ TextCharAttrib* pAttrib = MakeCharAttrib( *pCurPool, rPoolItem, nStart, nEnd );
+ DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" );
+ pNode->GetCharAttribs().InsertAttrib( pAttrib );
+// }
+// else
+// {
+// TextCharAttrib* pTmpAttrib =
+// pNode->GetCharAttribs().FindAnyAttrib( rPoolItem.Which() );
+// if ( pTmpAttrib ) // sonst benoetige ich es sowieso nicht....
+// {
+// aExcludeList.Insert( pTmpAttrib->GetItem() );
+// }
+// }
+}
+
+#pragma SEG_FUNCDEF(editdoc_40)
+
+void TextDoc::InsertAttrib( TextNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem )
+{
+ if ( nStart != nEnd )
+ {
+ InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
+ }
+ else
+ {
+ // Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle:
+ TextCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart );
+ if ( pAttr )
+ {
+ // Attribut entfernen....
+ pNode->GetCharAttribs().GetAttribs().Remove(
+ pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) );
+ }
+
+ // pruefen, ob ein 'gleiches' Attribut an der Stelle liegt.
+ pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart );
+ if ( pAttr )
+ {
+ if ( pAttr->IsInside( nStart ) ) // splitten
+ {
+ // ???????????????????????????????
+ // eigentlich noch pruefen, ob wirklich splittet, oder return !
+ // ???????????????????????????????
+ USHORT nOldEnd = pAttr->GetEnd();
+ pAttr->GetEnd() = nStart;
+ pAttr = MakeCharAttrib( *pCurPool, *(pAttr->GetItem()), nStart, nOldEnd );
+ pNode->GetCharAttribs().InsertAttrib( pAttr );
+ }
+ else if ( pAttr->GetEnd() == nStart )
+ {
+ DBG_ASSERT( !pAttr->IsEmpty(), "Doch noch ein leeres Attribut?" );
+ // pruefen, ob genau das gleiche Attribut
+ if ( *(pAttr->GetItem()) == rPoolItem )
+ return;
+ }
+ }
+ InsertAttrib( rPoolItem, pNode, nStart, nStart );
+ }
+}
+
+#pragma SEG_FUNCDEF(editdoc_41)
+
+void TextDoc::FindAttribs( TextNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet )
+{
+ DBG_ASSERT( pNode, "Wo soll ich suchen ?" );
+ DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" );
+
+ USHORT nAttr = 0;
+ TextCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
+ // keine Selection...
+ if ( nStartPos == nEndPos )
+ {
+ while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
+ {
+ const SfxPoolItem* pItem = 0;
+ // Attribut liegt dadrueber...
+ if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
+ pItem = pAttr->GetItem();
+ // Attribut endet hier, ist nicht leer
+ else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
+ {
+ if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) )
+ pItem = pAttr->GetItem();
+ }
+ // Attribut endet hier, ist leer
+ else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
+ {
+// if ( aExcludeList.FindAttrib( pAttr->GetItem()->Which() ) )
+ pItem = pAttr->GetItem();
+// else if ( pNode->Len() == 0 ) // Sonderfall
+// pItem = pAttr->GetItem();
+ }
+ // Attribut beginnt hier
+ else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
+ {
+ if ( nStartPos == 0 ) // Sonderfall
+ pItem = pAttr->GetItem();
+ }
+
+ if ( pItem )
+ {
+ USHORT nWhich = pItem->Which();
+ if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
+ {
+ rCurSet.Put( *pItem );
+ }
+ else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
+ {
+ const SfxPoolItem& rItem = rCurSet.Get( nWhich );
+ if ( rItem != *pItem )
+ {
+ rCurSet.InvalidateItem( nWhich );
+ }
+ }
+ }
+ nAttr++;
+ pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
+ }
+ }
+ else // Selektion
+ {
+ while ( pAttr && ( pAttr->GetStart() < nEndPos) )
+ {
+ const SfxPoolItem* pItem = 0;
+ // Attribut liegt dadrueber...
+ if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
+ pItem = pAttr->GetItem();
+ // Attribut startet mitten drin...
+ else if ( pAttr->GetStart() >= nStartPos )
+ {
+ // !!! pItem = pAttr->GetItem();
+ // einfach nur pItem reicht nicht, da ich z.B. bei Shadow
+ // niemals ein ungleiches Item finden wuerde, da ein solche
+ // seine Anwesenheit durch Abwesenheit repraesentiert!
+ // if ( ... )
+ // Es muesste geprueft werden, on genau das gleiche Attribut
+ // an der Bruchstelle aufsetzt, was recht aufwendig ist.
+ // Da ich beim Einfuegen von Attributen aber etwas optimiere
+ // tritt der Fall nicht so schnell auf...
+ // Also aus Geschwindigkeitsgruenden:
+ rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
+
+ }
+ // Attribut endet mitten drin...
+ else if ( pAttr->GetEnd() > nStartPos )
+ {
+ // pItem = pAttr->GetItem();
+ // s.o.
+
+ // -----------------31.05.95 16:01-------------------
+ // Ist falsch, wenn das gleiche Attribut sofort wieder
+ // eingestellt wird!
+ // => Sollte am besten nicht vorkommen, also gleich beim
+ // Setzen von Attributen richtig machen!
+ // --------------------------------------------------
+ rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
+ }
+
+ if ( pItem )
+ {
+ USHORT nWhich = pItem->Which();
+ if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
+ {
+ rCurSet.Put( *pItem );
+ }
+ else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
+ {
+ const SfxPoolItem& rItem = rCurSet.Get( nWhich );
+ if ( rItem != *pItem )
+ {
+ rCurSet.InvalidateItem( nWhich );
+ }
+ }
+ }
+ nAttr++;
+ pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
+ }
+ }
+}
+
+
+*/
+
+
diff --git a/svtools/source/edit/textdoc.hxx b/svtools/source/edit/textdoc.hxx
new file mode 100644
index 000000000000..0c875b4fe07f
--- /dev/null
+++ b/svtools/source/edit/textdoc.hxx
@@ -0,0 +1,148 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _TEXTDOC_HXX
+#define _TEXTDOC_HXX
+
+#include <svl/svarray.hxx>
+#include <svtools/textdata.hxx>
+#include <txtattr.hxx>
+
+#include <tools/debug.hxx>
+#include <tools/string.hxx>
+#include <tools/list.hxx>
+
+typedef TextCharAttrib* TextCharAttribPtr;
+SV_DECL_PTRARR_DEL( TextCharAttribs, TextCharAttribPtr, 0, 4 )
+
+class TextCharAttribList : private TextCharAttribs
+{
+private:
+ BOOL mbHasEmptyAttribs;
+
+ TextCharAttribList( const TextCharAttribList& ) : TextCharAttribs() {}
+
+public:
+ TextCharAttribList();
+ ~TextCharAttribList();
+
+ void Clear( BOOL bDestroyAttribs );
+ USHORT Count() const { return TextCharAttribs::Count(); }
+
+ TextCharAttrib* GetAttrib( USHORT n ) const { return TextCharAttribs::GetObject( n ); }
+ void RemoveAttrib( USHORT n ) { TextCharAttribs::Remove( n, 1 ); }
+
+ void InsertAttrib( TextCharAttrib* pAttrib );
+
+ void DeleteEmptyAttribs();
+ void ResortAttribs();
+
+ BOOL HasEmptyAttribs() const { return mbHasEmptyAttribs; }
+ BOOL& HasEmptyAttribs() { return mbHasEmptyAttribs; }
+
+ TextCharAttrib* FindAttrib( USHORT nWhich, USHORT nPos );
+ TextCharAttrib* FindNextAttrib( USHORT nWhich, USHORT nFromPos, USHORT nMaxPos = 0xFFFF ) const;
+ TextCharAttrib* FindEmptyAttrib( USHORT nWhich, USHORT nPos );
+ BOOL HasAttrib( USHORT nWhich ) const;
+ BOOL HasBoundingAttrib( USHORT nBound );
+
+#ifdef DBG_UTIL
+ BOOL DbgCheckAttribs();
+#endif
+};
+
+
+class TextNode
+{
+private:
+ String maText;
+ TextCharAttribList maCharAttribs;
+
+ TextNode( const TextNode& ) {;}
+protected:
+ void ExpandAttribs( USHORT nIndex, USHORT nNewChars );
+ void CollapsAttribs( USHORT nIndex, USHORT nDelChars );
+
+public:
+ TextNode( const String& rText );
+
+
+ const String& GetText() const { return maText; }
+
+ const TextCharAttribList& GetCharAttribs() const { return maCharAttribs; }
+ TextCharAttribList& GetCharAttribs() { return maCharAttribs; }
+
+ void InsertText( USHORT nPos, const String& rText );
+ void InsertText( USHORT nPos, sal_Unicode c );
+ void RemoveText( USHORT nPos, USHORT nChars );
+
+ TextNode* Split( USHORT nPos, BOOL bKeepEndigAttribs );
+ void Append( const TextNode& rNode );
+};
+
+class TextDoc
+{
+private:
+ ToolsList<TextNode*> maTextNodes;
+ USHORT mnLeftMargin;
+
+protected:
+ void DestroyTextNodes();
+
+public:
+ TextDoc();
+ ~TextDoc();
+
+ void Clear();
+
+ ToolsList<TextNode*>& GetNodes() { return maTextNodes; }
+ const ToolsList<TextNode*>& GetNodes() const { return maTextNodes; }
+
+ TextPaM RemoveChars( const TextPaM& rPaM, USHORT nChars );
+ TextPaM InsertText( const TextPaM& rPaM, sal_Unicode c );
+ TextPaM InsertText( const TextPaM& rPaM, const String& rStr );
+
+ TextPaM InsertParaBreak( const TextPaM& rPaM, BOOL bKeepEndingAttribs );
+ TextPaM ConnectParagraphs( TextNode* pLeft, TextNode* pRight );
+
+ ULONG GetTextLen( const sal_Unicode* pSep, const TextSelection* pSel = NULL ) const;
+ String GetText( const sal_Unicode* pSep ) const;
+ String GetText( ULONG nPara ) const;
+
+ void SetLeftMargin( USHORT n ) { mnLeftMargin = n; }
+ USHORT GetLeftMargin() const { return mnLeftMargin; }
+
+// BOOL RemoveAttribs( TextNode* pNode, USHORT nStart, USHORT nEnd ), USHORT nWhich = 0 );
+// BOOL RemoveAttribs( TextNode* pNode, USHORT nStart, USHORT nEnd, TextCharAttrib*& rpStarting, TextCharAttrib*& rpEnding, USHORT nWhich = 0 );
+// void InsertAttrib( const EditCharAttrib* pAttr );
+// void InsertAttribInSelection( const EditCharAttrib* pAttr );
+// void FindAttribs( TextNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet );
+
+ BOOL IsValidPaM( const TextPaM& rPaM );
+};
+
+#endif // _TEXTDOC_HXX
diff --git a/svtools/source/edit/texteng.cxx b/svtools/source/edit/texteng.cxx
new file mode 100644
index 000000000000..e0e136089d78
--- /dev/null
+++ b/svtools/source/edit/texteng.cxx
@@ -0,0 +1,3303 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+
+#include <tools/stream.hxx>
+
+#include <svtools/texteng.hxx>
+#include <svtools/textview.hxx>
+#include <textdoc.hxx>
+#include <textdat2.hxx>
+#include <textundo.hxx>
+#include <textund2.hxx>
+#include <svl/ctloptions.hxx>
+#include <vcl/window.hxx>
+
+#include <vcl/edit.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+
+#ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
+#include <com/sun/star/i18n/WordType.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_
+#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
+#endif
+#include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+
+#include <comphelper/processfactory.hxx>
+
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/unohelp.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/unohelp.hxx>
+#include <vcl/metric.hxx>
+
+#include <unicode/ubidi.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+
+typedef TextView* TextViewPtr;
+SV_DECL_PTRARR( TextViews, TextViewPtr, 0, 1 )
+// SV_IMPL_PTRARR( TextViews, TextViewPtr );
+
+SV_DECL_VARARR_SORT( TESortedPositions, ULONG, 16, 8 )
+SV_IMPL_VARARR_SORT( TESortedPositions, ULONG )
+
+#define RESDIFF 10
+#define SCRLRANGE 20 // 1/20 der Breite/Hoehe scrollen, wenn im QueryDrop
+
+
+ // -------------------------------------------------------------------------
+// (-) class TextEngine
+// -------------------------------------------------------------------------
+TextEngine::TextEngine()
+{
+ mpDoc = 0;
+ mpTEParaPortions = 0;
+
+ mpViews = new TextViews;
+ mpActiveView = NULL;
+
+ mbIsFormatting = FALSE;
+ mbFormatted = FALSE;
+ mbUpdate = TRUE;
+ mbModified = FALSE;
+ mbUndoEnabled = FALSE;
+ mbIsInUndo = FALSE;
+ mbDowning = FALSE;
+ mbRightToLeft = FALSE;
+ mbHasMultiLineParas = FALSE;
+
+ meAlign = TXTALIGN_LEFT;
+
+ mnMaxTextWidth = 0;
+ mnMaxTextLen = 0;
+ mnCurTextWidth = 0xFFFFFFFF;
+ mnCurTextHeight = 0;
+
+ mpUndoManager = NULL;
+ mpIMEInfos = NULL;
+ mpLocaleDataWrapper = NULL;
+
+ mpIdleFormatter = new IdleFormatter;
+ mpIdleFormatter->SetTimeoutHdl( LINK( this, TextEngine, IdleFormatHdl ) );
+
+ mpRefDev = new VirtualDevice;
+
+ ImpInitLayoutMode( mpRefDev );
+
+ ImpInitDoc();
+
+ maTextColor = COL_BLACK;
+ Font aFont;
+ aFont.SetTransparent( FALSE );
+ Color aFillColor( aFont.GetFillColor() );
+ aFillColor.SetTransparency( 0 );
+ aFont.SetFillColor( aFillColor );
+ SetFont( aFont );
+}
+
+TextEngine::~TextEngine()
+{
+ mbDowning = TRUE;
+
+ delete mpIdleFormatter;
+ delete mpDoc;
+ delete mpTEParaPortions;
+ delete mpViews; // nur die Liste, nicht die Vies
+ delete mpRefDev;
+ delete mpUndoManager;
+ delete mpIMEInfos;
+ delete mpLocaleDataWrapper;
+}
+
+void TextEngine::InsertView( TextView* pTextView )
+{
+ mpViews->Insert( pTextView, mpViews->Count() );
+ pTextView->SetSelection( TextSelection() );
+
+ if ( !GetActiveView() )
+ SetActiveView( pTextView );
+}
+
+void TextEngine::RemoveView( TextView* pTextView )
+{
+ USHORT nPos = mpViews->GetPos( pTextView );
+ if( nPos != USHRT_MAX )
+ {
+ pTextView->HideCursor();
+ mpViews->Remove( nPos, 1 );
+ if ( pTextView == GetActiveView() )
+ SetActiveView( 0 );
+ }
+}
+
+USHORT TextEngine::GetViewCount() const
+{
+ return mpViews->Count();
+}
+
+TextView* TextEngine::GetView( USHORT nView ) const
+{
+ return mpViews->GetObject( nView );
+}
+
+TextView* TextEngine::GetActiveView() const
+{
+ return mpActiveView;
+}
+
+void TextEngine::SetActiveView( TextView* pTextView )
+{
+ if ( pTextView != mpActiveView )
+ {
+ if ( mpActiveView )
+ mpActiveView->HideSelection();
+
+ mpActiveView = pTextView;
+
+ if ( mpActiveView )
+ mpActiveView->ShowSelection();
+ }
+}
+
+void TextEngine::SetFont( const Font& rFont )
+{
+ if ( rFont != maFont )
+ {
+ maFont = rFont;
+ // #i40221# As the font's color now defaults to transparent (since i35764)
+ // we have to choose a useful textcolor in this case.
+ // Otherwise maTextColor and maFont.GetColor() are both transparent....
+ if( rFont.GetColor() == COL_TRANSPARENT )
+ maTextColor = COL_BLACK;
+ else
+ maTextColor = rFont.GetColor();
+
+ // Wegen Selektion keinen Transparenten Font zulassen...
+ // (Sonst spaeter in ImplPaint den Hintergrund anders loeschen...)
+ maFont.SetTransparent( FALSE );
+ // Tell VCL not to use the font color, use text color from OutputDevice
+ maFont.SetColor( COL_TRANSPARENT );
+ Color aFillColor( maFont.GetFillColor() );
+ aFillColor.SetTransparency( 0 );
+ maFont.SetFillColor( aFillColor );
+
+ maFont.SetAlign( ALIGN_TOP );
+ mpRefDev->SetFont( maFont);
+ Size aTextSize;
+ aTextSize.Width() = mpRefDev->GetTextWidth( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( " " ) ) );
+ aTextSize.Height() = mpRefDev->GetTextHeight();
+ if ( !aTextSize.Width() )
+ aTextSize.Width() = mpRefDev->GetTextWidth( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "XXXX" ) ) );
+
+ mnDefTab = (USHORT)aTextSize.Width();
+ if ( !mnDefTab )
+ mnDefTab = 1;
+ mnCharHeight = (USHORT)aTextSize.Height();
+/*
+ // #93746# Doesn't work with CJK HalfWidth/FullWidth
+ FontMetric aRealFont( mpRefDev->GetFontMetric() );
+ if ( aRealFont.GetPitch() == PITCH_FIXED )
+ {
+ String aX100;
+ aX100.Fill( 100, 'X' );
+ mnFixCharWidth100 = (USHORT)mpRefDev->GetTextWidth( aX100 );
+ }
+ else
+*/
+ mnFixCharWidth100 = 0;
+
+ FormatFullDoc();
+ UpdateViews();
+
+ for ( USHORT nView = mpViews->Count(); nView; )
+ {
+ TextView* pView = mpViews->GetObject( --nView );
+ pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
+ }
+ }
+}
+
+void TextEngine::SetDefTab( USHORT nDefTab )
+{
+ mnDefTab = nDefTab;
+ // evtl neu setzen?
+}
+
+void TextEngine::SetMaxTextLen( ULONG nLen )
+{
+ mnMaxTextLen = nLen;
+}
+
+void TextEngine::SetMaxTextWidth( ULONG nMaxWidth )
+{
+ if ( nMaxWidth != mnMaxTextWidth )
+ {
+ mnMaxTextWidth = Min( nMaxWidth, (ULONG)0x7FFFFFFF );
+ FormatFullDoc();
+ UpdateViews();
+ }
+}
+
+static sal_Unicode static_aLFText[] = { '\n', 0 };
+static sal_Unicode static_aCRText[] = { '\r', 0 };
+static sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 };
+
+static inline const sal_Unicode* static_getLineEndText( LineEnd aLineEnd )
+{
+ const sal_Unicode* pRet = NULL;
+
+ switch( aLineEnd )
+ {
+ case LINEEND_LF: pRet = static_aLFText;break;
+ case LINEEND_CR: pRet = static_aCRText;break;
+ case LINEEND_CRLF: pRet = static_aCRLFText;break;
+ }
+ return pRet;
+}
+
+void TextEngine::ReplaceText(const TextSelection& rSel, const String& rText)
+{
+ ImpInsertText( rSel, rText );
+}
+
+String TextEngine::GetText( LineEnd aSeparator ) const
+{
+ return mpDoc->GetText( static_getLineEndText( aSeparator ) );
+}
+
+String TextEngine::GetTextLines( LineEnd aSeparator ) const
+{
+ String aText;
+ ULONG nParas = mpTEParaPortions->Count();
+ const sal_Unicode* pSep = static_getLineEndText( aSeparator );
+ for ( ULONG nP = 0; nP < nParas; nP++ )
+ {
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP );
+
+ USHORT nLines = pTEParaPortion->GetLines().Count();
+ for ( USHORT nL = 0; nL < nLines; nL++ )
+ {
+ TextLine* pLine = pTEParaPortion->GetLines()[nL];
+ aText += pTEParaPortion->GetNode()->GetText().Copy( pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() );
+ if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) )
+ aText += pSep;
+ }
+ }
+ return aText;
+}
+
+String TextEngine::GetText( ULONG nPara ) const
+{
+ return mpDoc->GetText( nPara );
+}
+
+ULONG TextEngine::GetTextLen( LineEnd aSeparator ) const
+{
+ return mpDoc->GetTextLen( static_getLineEndText( aSeparator ) );
+}
+
+ULONG TextEngine::GetTextLen( const TextSelection& rSel, LineEnd aSeparator ) const
+{
+ TextSelection aSel( rSel );
+ aSel.Justify();
+ ValidateSelection( aSel );
+ return mpDoc->GetTextLen( static_getLineEndText( aSeparator ), &aSel );
+}
+
+USHORT TextEngine::GetTextLen( ULONG nPara ) const
+{
+ return mpDoc->GetNodes().GetObject( nPara )->GetText().Len();
+}
+
+void TextEngine::SetUpdateMode( BOOL bUpdate )
+{
+ if ( bUpdate != mbUpdate )
+ {
+ mbUpdate = bUpdate;
+ if ( mbUpdate )
+ {
+ FormatAndUpdate( GetActiveView() );
+ if ( GetActiveView() )
+ GetActiveView()->ShowCursor();
+ }
+ }
+}
+
+BOOL TextEngine::DoesKeyMoveCursor( const KeyEvent& rKeyEvent )
+{
+ BOOL bDoesMove = FALSE;
+
+ switch ( rKeyEvent.GetKeyCode().GetCode() )
+ {
+ 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() )
+ bDoesMove = TRUE;
+ }
+ break;
+ }
+ return bDoesMove;
+}
+
+BOOL TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent )
+{
+ BOOL bDoesChange = FALSE;
+
+ KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
+ if ( eFunc != KEYFUNC_DONTKNOW )
+ {
+ switch ( eFunc )
+ {
+ case KEYFUNC_UNDO:
+ case KEYFUNC_REDO:
+ case KEYFUNC_CUT:
+ case KEYFUNC_PASTE: bDoesChange = TRUE;
+ break;
+ default: // wird dann evtl. unten bearbeitet.
+ eFunc = KEYFUNC_DONTKNOW;
+ }
+ }
+ if ( eFunc == KEYFUNC_DONTKNOW )
+ {
+ switch ( rKeyEvent.GetKeyCode().GetCode() )
+ {
+ case KEY_DELETE:
+ case KEY_BACKSPACE:
+ {
+ if ( !rKeyEvent.GetKeyCode().IsMod2() )
+ bDoesChange = TRUE;
+ }
+ break;
+ case KEY_RETURN:
+ case KEY_TAB:
+ {
+ if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() )
+ bDoesChange = TRUE;
+ }
+ break;
+ default:
+ {
+ bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent );
+ }
+ }
+ }
+ return bDoesChange;
+}
+
+BOOL TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent )
+{
+ if( rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 &&
+ KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#:
+ KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) ) // check for Ctrl and Alt separately
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void TextEngine::ImpInitDoc()
+{
+ if ( mpDoc )
+ mpDoc->Clear();
+ else
+ mpDoc = new TextDoc;
+
+ delete mpTEParaPortions;
+ mpTEParaPortions = new TEParaPortions;
+
+ TextNode* pNode = new TextNode( String() );
+ mpDoc->GetNodes().Insert( pNode, 0 );
+
+ TEParaPortion* pIniPortion = new TEParaPortion( pNode );
+ mpTEParaPortions->Insert( pIniPortion, (ULONG)0 );
+
+ mbFormatted = FALSE;
+
+ ImpParagraphRemoved( TEXT_PARA_ALL );
+ ImpParagraphInserted( 0 );
+}
+
+String TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const
+{
+ String aText;
+
+ if ( !rSel.HasRange() )
+ return aText;
+
+ TextSelection aSel( rSel );
+ aSel.Justify();
+
+ ULONG nStartPara = aSel.GetStart().GetPara();
+ ULONG nEndPara = aSel.GetEnd().GetPara();
+ const sal_Unicode* pSep = static_getLineEndText( aSeparator );
+ for ( ULONG nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; nNode++ )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nNode );
+
+ USHORT nStartPos = 0;
+ USHORT nEndPos = pNode->GetText().Len();
+ if ( nNode == nStartPara )
+ nStartPos = aSel.GetStart().GetIndex();
+ if ( nNode == nEndPara ) // kann auch == nStart sein!
+ nEndPos = aSel.GetEnd().GetIndex();
+
+ aText += pNode->GetText().Copy( nStartPos, nEndPos-nStartPos );
+ if ( nNode < nEndPara )
+ aText += pSep;
+ }
+ return aText;
+}
+
+void TextEngine::ImpRemoveText()
+{
+ ImpInitDoc();
+
+ TextPaM aStartPaM( 0, 0 );
+ TextSelection aEmptySel( aStartPaM, aStartPaM );
+ for ( USHORT nView = 0; nView < mpViews->Count(); nView++ )
+ {
+ TextView* pView = mpViews->GetObject( nView );
+ pView->ImpSetSelection( aEmptySel );
+ }
+ ResetUndo();
+}
+
+void TextEngine::SetText( const XubString& rText )
+{
+ ImpRemoveText();
+
+ BOOL bUndoCurrentlyEnabled = IsUndoEnabled();
+ // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden.
+ EnableUndo( FALSE );
+
+ TextPaM aStartPaM( 0, 0 );
+ TextSelection aEmptySel( aStartPaM, aStartPaM );
+
+ TextPaM aPaM = aStartPaM;
+ if ( rText.Len() )
+ aPaM = ImpInsertText( aEmptySel, rText );
+
+ for ( USHORT nView = 0; nView < mpViews->Count(); nView++ )
+ {
+ TextView* pView = mpViews->GetObject( nView );
+ pView->ImpSetSelection( aEmptySel );
+
+ // Wenn kein Text, dann auch Kein Format&Update
+ // => Der Text bleibt stehen.
+ if ( !rText.Len() && GetUpdateMode() )
+ pView->Invalidate();
+ }
+
+ if( !rText.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht.
+ mnCurTextHeight = 0;
+
+ FormatAndUpdate();
+
+ EnableUndo( bUndoCurrentlyEnabled );
+ DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" );
+}
+
+
+void TextEngine::CursorMoved( ULONG nNode )
+{
+ // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer!
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nNode );
+ if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && pNode->GetText().Len() )
+ pNode->GetCharAttribs().DeleteEmptyAttribs();
+}
+
+void TextEngine::ImpRemoveChars( const TextPaM& rPaM, USHORT nChars, SfxUndoAction* )
+{
+ DBG_ASSERT( nChars, "ImpRemoveChars - 0 Chars?!" );
+ if ( IsUndoEnabled() && !IsInUndo() )
+ {
+ // Attribute muessen hier vorm RemoveChars fuer UNDO gesichert werden!
+ TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
+ XubString aStr( pNode->GetText().Copy( rPaM.GetIndex(), nChars ) );
+
+ // Pruefen, ob Attribute geloescht oder geaendert werden:
+ USHORT nStart = rPaM.GetIndex();
+ USHORT nEnd = nStart + nChars;
+ for ( USHORT nAttr = pNode->GetCharAttribs().Count(); nAttr; )
+ {
+ TextCharAttrib* pAttr = pNode->GetCharAttribs().GetAttrib( --nAttr );
+ if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) )
+ {
+// TextSelection aSel( rPaM );
+// aSel.GetEnd().GetIndex() += nChars;
+// TextUndoSetAttribs* pAttrUndo = CreateAttribUndo( aSel );
+// InsertUndo( pAttrUndo );
+ break; // for
+ }
+ }
+// if ( pCurUndo && ( CreateTextPaM( pCurUndo->GetEPaM() ) == rPaM ) )
+// pCurUndo->GetStr() += aStr;
+// else
+ InsertUndo( new TextUndoRemoveChars( this, rPaM, aStr ) );
+ }
+
+ mpDoc->RemoveChars( rPaM, nChars );
+ ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars );
+}
+
+TextPaM TextEngine::ImpConnectParagraphs( ULONG nLeft, ULONG nRight )
+{
+ DBG_ASSERT( nLeft != nRight, "Den gleichen Absatz zusammenfuegen ?" );
+
+ TextNode* pLeft = mpDoc->GetNodes().GetObject( nLeft );
+ TextNode* pRight = mpDoc->GetNodes().GetObject( nRight );
+
+ if ( IsUndoEnabled() && !IsInUndo() )
+ InsertUndo( new TextUndoConnectParas( this, nLeft, pLeft->GetText().Len() ) );
+
+ // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg.
+ TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft );
+ TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight );
+ DBG_ASSERT( pLeft && pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" );
+ DBG_ASSERT( pRight && pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" );
+
+ TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight );
+ ImpParagraphRemoved( nRight );
+
+ pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->GetText().Len() );
+
+ mpTEParaPortions->Remove( nRight );
+ delete pRightPortion;
+ // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht.
+
+ return aPaM;
+}
+
+TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel )
+{
+ if ( !rSel.HasRange() )
+ return rSel.GetStart();
+
+ TextSelection aSel( rSel );
+ aSel.Justify();
+ TextPaM aStartPaM( aSel.GetStart() );
+ TextPaM aEndPaM( aSel.GetEnd() );
+
+ CursorMoved( aStartPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden...
+ CursorMoved( aEndPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden...
+
+ DBG_ASSERT( mpDoc->IsValidPaM( aStartPaM ), "Index im Wald in ImpDeleteText" );
+ DBG_ASSERT( mpDoc->IsValidPaM( aEndPaM ), "Index im Wald in ImpDeleteText" );
+
+ ULONG nStartNode = aStartPaM.GetPara();
+ ULONG nEndNode = aEndPaM.GetPara();
+
+ // Alle Nodes dazwischen entfernen....
+ for ( ULONG z = nStartNode+1; z < nEndNode; z++ )
+ {
+ // Immer nStartNode+1, wegen Remove()!
+ ImpRemoveParagraph( nStartNode+1 );
+ }
+
+ if ( nStartNode != nEndNode )
+ {
+ // Den Rest des StartNodes...
+ TextNode* pLeft = mpDoc->GetNodes().GetObject( nStartNode );
+ USHORT nChars = pLeft->GetText().Len() - aStartPaM.GetIndex();
+ if ( nChars )
+ {
+ ImpRemoveChars( aStartPaM, nChars );
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode );
+ DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(3)" );
+ pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), pLeft->GetText().Len() );
+ }
+
+ // Den Anfang des EndNodes....
+ nEndNode = nStartNode+1; // Die anderen Absaetze wurden geloescht
+ nChars = aEndPaM.GetIndex();
+ if ( nChars )
+ {
+ aEndPaM.GetPara() = nEndNode;
+ aEndPaM.GetIndex() = 0;
+ ImpRemoveChars( aEndPaM, nChars );
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode );
+ DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(4)" );
+ pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->GetText().Len() );
+ }
+
+ // Zusammenfuegen....
+ aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode );
+ }
+ else
+ {
+ USHORT nChars;
+ nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex();
+ ImpRemoveChars( aStartPaM, nChars );
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode );
+ DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(5)" );
+ pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
+ }
+
+// UpdateSelections();
+ TextModified();
+ return aStartPaM;
+}
+
+void TextEngine::ImpRemoveParagraph( ULONG nPara )
+{
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
+
+ // Der Node wird vom Undo verwaltet und ggf. zerstoert!
+ /* delete */ mpDoc->GetNodes().Remove( nPara );
+ if ( IsUndoEnabled() && !IsInUndo() )
+ InsertUndo( new TextUndoDelPara( this, pNode, nPara ) );
+ else
+ delete pNode;
+
+ mpTEParaPortions->Remove( nPara );
+ delete pPortion;
+
+ ImpParagraphRemoved( nPara );
+}
+
+uno::Reference < i18n::XExtendedInputSequenceChecker > TextEngine::GetInputSequenceChecker() const
+{
+ uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
+// if ( !xISC.is() )
+ {
+ uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
+ uno::Reference< uno::XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) );
+ if ( xI.is() )
+ {
+ Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XExtendedInputSequenceChecker >*)0) );
+ x >>= xISC;
+ }
+ }
+ return xISC;
+}
+
+BOOL TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const
+{
+ uno::Reference< i18n::XBreakIterator > xBI = ((TextEngine *) this)->GetBreakIterator();
+ SvtCTLOptions aCTLOptions;
+
+ // get the index that really is first
+ USHORT nFirstPos = rCurSel.GetStart().GetIndex();
+ USHORT nMaxPos = rCurSel.GetEnd().GetIndex();
+ if (nMaxPos < nFirstPos)
+ nFirstPos = nMaxPos;
+
+ sal_Bool bIsSequenceChecking =
+ aCTLOptions.IsCTLFontEnabled() &&
+ aCTLOptions.IsCTLSequenceChecking() &&
+ nFirstPos != 0 && /* first char needs not to be checked */
+ xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rtl::OUString( c ), 0 );
+
+ return bIsSequenceChecking;
+}
+
+TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, BOOL bOverwrite )
+{
+ return ImpInsertText( c, rCurSel, bOverwrite, sal_False );
+}
+
+TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, BOOL bOverwrite, BOOL bIsUserInput )
+{
+ DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" );
+ DBG_ASSERT( c != '\r', "Zeilenumbruch bei InsertText ?" );
+
+ TextPaM aPaM( rCurSel.GetStart() );
+ TextNode* pNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+
+ if ( pNode->GetText().Len() < STRING_MAXLEN )
+ {
+ BOOL bDoOverwrite = ( bOverwrite &&
+ ( aPaM.GetIndex() < pNode->GetText().Len() ) ) ? TRUE : FALSE;
+
+ BOOL bUndoAction = ( rCurSel.HasRange() || bDoOverwrite );
+
+ if ( bUndoAction )
+ UndoActionStart( TEXTUNDO_INSERT );
+
+ if ( rCurSel.HasRange() )
+ {
+ aPaM = ImpDeleteText( rCurSel );
+ }
+ else if ( bDoOverwrite )
+ {
+ // Wenn Selektion, dann kein Zeichen ueberschreiben
+ TextSelection aTmpSel( aPaM );
+ aTmpSel.GetEnd().GetIndex()++;
+ ImpDeleteText( aTmpSel );
+ }
+
+ if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel ))
+ {
+ uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker();
+ SvtCTLOptions aCTLOptions;
+
+ if (xISC.is())
+ {
+ xub_StrLen nTmpPos = aPaM.GetIndex();
+ sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ?
+ i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
+
+ // the text that needs to be checked is only the one
+ // before the current cursor position
+ rtl::OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).Copy(0, nTmpPos) );
+ rtl::OUString aNewText( aOldText );
+ if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace())
+ {
+ xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode );
+
+ // find position of first character that has changed
+ sal_Int32 nOldLen = aOldText.getLength();
+ sal_Int32 nNewLen = aNewText.getLength();
+ const sal_Unicode *pOldTxt = aOldText.getStr();
+ const sal_Unicode *pNewTxt = aNewText.getStr();
+ sal_Int32 nChgPos = 0;
+ while ( nChgPos < nOldLen && nChgPos < nNewLen &&
+ pOldTxt[nChgPos] == pNewTxt[nChgPos] )
+ ++nChgPos;
+
+ xub_StrLen nChgLen = static_cast< xub_StrLen >(nNewLen - nChgPos);
+ String aChgText( aNewText.copy( nChgPos ), nChgLen );
+
+ // select text from first pos to be changed to current pos
+ TextSelection aSel( TextPaM( aPaM.GetPara(), (USHORT) nChgPos ), aPaM );
+
+ if (aChgText.Len())
+ // ImpInsertText implicitly handles undo...
+ return ImpInsertText( aSel, aChgText );
+ else
+ return aPaM;
+ }
+ else
+ {
+ // should the character be ignored (i.e. not get inserted) ?
+ if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode ))
+ return aPaM; // nothing to be done -> no need for undo
+ }
+ }
+
+ // at this point now we will insert the character 'normally' some lines below...
+ }
+
+
+ if ( IsUndoEnabled() && !IsInUndo() )
+ {
+ TextUndoInsertChars* pNewUndo = new TextUndoInsertChars( this, aPaM, c );
+ BOOL bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? TRUE : FALSE;
+ InsertUndo( pNewUndo, bTryMerge );
+ }
+
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() );
+ pPortion->MarkInvalid( aPaM.GetIndex(), 1 );
+ if ( c == '\t' )
+ pPortion->SetNotSimpleInvalid();
+ aPaM = mpDoc->InsertText( aPaM, c );
+ ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 );
+
+ TextModified();
+
+ if ( bUndoAction )
+ UndoActionEnd( TEXTUNDO_INSERT );
+ }
+
+ return aPaM;
+}
+
+
+TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString& rStr )
+{
+ UndoActionStart( TEXTUNDO_INSERT );
+
+ TextPaM aPaM;
+
+ if ( rCurSel.HasRange() )
+ aPaM = ImpDeleteText( rCurSel );
+ else
+ aPaM = rCurSel.GetEnd();
+
+ XubString aText( rStr );
+ aText.ConvertLineEnd( LINEEND_LF );
+
+ USHORT nStart = 0;
+ while ( nStart < aText.Len() )
+ {
+ USHORT nEnd = aText.Search( LINE_SEP, nStart );
+ if ( nEnd == STRING_NOTFOUND )
+ nEnd = aText.Len(); // nicht dereferenzieren!
+
+ // Start == End => Leerzeile
+ if ( nEnd > nStart )
+ {
+ ULONG nL = aPaM.GetIndex();
+ nL += ( nEnd-nStart );
+ if ( nL > STRING_MAXLEN )
+ {
+ USHORT nDiff = (USHORT) (nL-STRING_MAXLEN);
+ nEnd = nEnd - nDiff;
+ }
+
+ XubString aLine( aText, nStart, nEnd-nStart );
+ if ( IsUndoEnabled() && !IsInUndo() )
+ InsertUndo( new TextUndoInsertChars( this, aPaM, aLine ) );
+
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() );
+ pPortion->MarkInvalid( aPaM.GetIndex(), aLine.Len() );
+ if ( aLine.Search( '\t' ) != STRING_NOTFOUND )
+ pPortion->SetNotSimpleInvalid();
+
+ aPaM = mpDoc->InsertText( aPaM, aLine );
+ ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.Len(), aLine.Len() );
+
+ }
+ if ( nEnd < aText.Len() )
+ aPaM = ImpInsertParaBreak( aPaM );
+
+ nStart = nEnd+1;
+
+ if ( nStart < nEnd ) // #108611# overflow
+ break;
+ }
+
+ UndoActionEnd( TEXTUNDO_INSERT );
+
+ TextModified();
+ return aPaM;
+}
+
+TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel, BOOL bKeepEndingAttribs )
+{
+ TextPaM aPaM;
+ if ( rCurSel.HasRange() )
+ aPaM = ImpDeleteText( rCurSel );
+ else
+ aPaM = rCurSel.GetEnd();
+
+ return ImpInsertParaBreak( aPaM, bKeepEndingAttribs );
+}
+
+TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM, BOOL bKeepEndingAttribs )
+{
+ if ( IsUndoEnabled() && !IsInUndo() )
+ InsertUndo( new TextUndoSplitPara( this, rPaM.GetPara(), rPaM.GetIndex() ) );
+
+ TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
+ BOOL bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().Len();
+
+ TextPaM aPaM( mpDoc->InsertParaBreak( rPaM, bKeepEndingAttribs ) );
+
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
+ DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" );
+ pPortion->MarkInvalid( rPaM.GetIndex(), 0 );
+
+ TextNode* pNewNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() );
+ TEParaPortion* pNewPortion = new TEParaPortion( pNewNode );
+ mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() );
+ ImpParagraphInserted( aPaM.GetPara() );
+
+ CursorMoved( rPaM.GetPara() ); // falls leeres Attribut entstanden.
+ TextModified();
+
+ if ( bFirstParaContentChanged )
+ Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, rPaM.GetPara() ) );
+
+ return aPaM;
+}
+
+Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, BOOL bSpecial )
+{
+ DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: PaMtoEditCursor" );
+
+ Rectangle aEditCursor;
+ long nY = 0;
+
+ if ( !mbHasMultiLineParas )
+ {
+ nY = rPaM.GetPara() * mnCharHeight;
+ }
+ else
+ {
+ for ( ULONG nPortion = 0; nPortion < rPaM.GetPara(); nPortion++ )
+ {
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion);
+ nY += pPortion->GetLines().Count() * mnCharHeight;
+ }
+ }
+
+ aEditCursor = GetEditCursor( rPaM, bSpecial );
+ aEditCursor.Top() += nY;
+ aEditCursor.Bottom() += nY;
+ return aEditCursor;
+}
+
+Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, BOOL bSpecial, BOOL bPreferPortionStart )
+{
+ if ( !IsFormatted() && !IsFormatting() )
+ FormatAndUpdate();
+
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
+ //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
+
+ /*
+ bSpecial: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile,
+ am Ende der Zeile bleiben, nicht am Anfang der naechsten.
+ Zweck: - END => wirklich hinter das letzte Zeichen
+ - Selektion....
+ bSpecial: If behind the last character of a made up line, stay at the
+ end of the line, not at the start of the next line.
+ Purpose: - really END = > behind the last character
+ - to selection...
+
+ */
+
+ long nY = 0;
+ USHORT nCurIndex = 0;
+ TextLine* pLine = 0;
+ for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
+ {
+ TextLine* pTmpLine = pPortion->GetLines().GetObject( nLine );
+ if ( ( pTmpLine->GetStart() == rPaM.GetIndex() ) || ( pTmpLine->IsIn( rPaM.GetIndex(), bSpecial ) ) )
+ {
+ pLine = pTmpLine;
+ break;
+ }
+
+ nCurIndex = nCurIndex + pTmpLine->GetLen();
+ nY += mnCharHeight;
+ }
+ if ( !pLine )
+ {
+ // Cursor am Ende des Absatzes.
+ DBG_ASSERT( rPaM.GetIndex() == nCurIndex, "Index voll daneben in GetEditCursor!" );
+
+ pLine = pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1 );
+ nY -= mnCharHeight;
+ nCurIndex = nCurIndex - pLine->GetLen();
+ }
+
+ Rectangle aEditCursor;
+
+ aEditCursor.Top() = nY;
+ nY += mnCharHeight;
+ aEditCursor.Bottom() = nY-1;
+
+ // innerhalb der Zeile suchen....
+ long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart );
+ aEditCursor.Left() = aEditCursor.Right() = nX;
+ return aEditCursor;
+}
+
+long TextEngine::ImpGetXPos( ULONG nPara, TextLine* pLine, USHORT nIndex, BOOL bPreferPortionStart )
+{
+ DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "ImpGetXPos muss richtig gerufen werden!" );
+
+ BOOL bDoPreferPortionStart = bPreferPortionStart;
+ // Assure that the portion belongs to this line:
+ if ( nIndex == pLine->GetStart() )
+ bDoPreferPortionStart = TRUE;
+ else if ( nIndex == pLine->GetEnd() )
+ bDoPreferPortionStart = FALSE;
+
+ TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
+
+ USHORT nTextPortionStart = 0;
+ USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart );
+
+ DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " );
+
+ TETextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion );
+
+ long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion );
+
+ long nPortionTextWidth = pPortion->GetWidth();
+
+ if ( nTextPortionStart != nIndex )
+ {
+ // Search within portion...
+ if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) )
+ {
+ // End of Portion
+ if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) ||
+ ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) ||
+ ( IsRightToLeft() && pPortion->IsRightToLeft() ) )
+ {
+ nX += nPortionTextWidth;
+ if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().Count() ) )
+ {
+ TETextPortion* pNextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion+1 );
+ if ( ( pNextPortion->GetKind() != PORTIONKIND_TAB ) && (
+ ( !IsRightToLeft() && pNextPortion->IsRightToLeft() ) ||
+ ( IsRightToLeft() && !pNextPortion->IsRightToLeft() ) ) )
+ {
+// nX += pNextPortion->GetWidth();
+ // End of the tab portion, use start of next for cursor pos
+ DBG_ASSERT( !bPreferPortionStart, "ImpGetXPos - How can we this tab portion here???" );
+ nX = ImpGetXPos( nPara, pLine, nIndex, TRUE );
+ }
+
+ }
+ }
+ }
+ else if ( pPortion->GetKind() == PORTIONKIND_TEXT )
+ {
+ DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new ImpGetXPos()" );
+
+ long nPosInPortion = (long)CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart );
+
+ if ( ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) ||
+ ( IsRightToLeft() && pPortion->IsRightToLeft() ) )
+ {
+ nX += nPosInPortion;
+ }
+ else
+ {
+ nX += nPortionTextWidth - nPosInPortion;
+ }
+ }
+ }
+ else // if ( nIndex == pLine->GetStart() )
+ {
+ if ( ( pPortion->GetKind() != PORTIONKIND_TAB ) &&
+ ( ( !IsRightToLeft() && pPortion->IsRightToLeft() ) ||
+ ( IsRightToLeft() && !pPortion->IsRightToLeft() ) ) )
+ {
+ nX += nPortionTextWidth;
+ }
+ }
+
+ return nX;
+}
+
+const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, USHORT nWhich ) const
+{
+ const TextAttrib* pAttr = NULL;
+ const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich );
+ if ( pCharAttr )
+ pAttr = &pCharAttr->GetAttr();
+ return pAttr;
+}
+
+const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, USHORT nWhich ) const
+{
+ const TextCharAttrib* pAttr = NULL;
+ TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
+ if ( pNode && ( rPaM.GetIndex() < pNode->GetText().Len() ) )
+ pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() );
+ return pAttr;
+}
+
+BOOL TextEngine::HasAttrib( USHORT nWhich ) const
+{
+ BOOL bAttr = FALSE;
+ for ( ULONG n = mpDoc->GetNodes().Count(); --n && !bAttr; )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( n );
+ bAttr = pNode->GetCharAttribs().HasAttrib( nWhich );
+ }
+ return bAttr;
+}
+
+TextPaM TextEngine::GetPaM( const Point& rDocPos, BOOL bSmart )
+{
+ DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: GetPaM" );
+
+ long nY = 0;
+ for ( ULONG nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ )
+ {
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
+ long nTmpHeight = pPortion->GetLines().Count() * mnCharHeight;
+ nY += nTmpHeight;
+ if ( nY > rDocPos.Y() )
+ {
+ nY -= nTmpHeight;
+ Point aPosInPara( rDocPos );
+ aPosInPara.Y() -= nY;
+
+ TextPaM aPaM( nPortion, 0 );
+ aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara, bSmart );
+ return aPaM;
+ }
+ }
+
+ // Nicht gefunden - Dann den letzten sichtbare...
+ ULONG nLastNode = mpDoc->GetNodes().Count() - 1;
+ TextNode* pLast = mpDoc->GetNodes().GetObject( nLastNode );
+ return TextPaM( nLastNode, pLast->GetText().Len() );
+}
+
+USHORT TextEngine::ImpFindIndex( ULONG nPortion, const Point& rPosInPara, BOOL bSmart )
+{
+ DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" );
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
+
+ USHORT nCurIndex = 0;
+
+ long nY = 0;
+ TextLine* pLine = 0;
+ USHORT nLine;
+ for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
+ {
+ TextLine* pTmpLine = pPortion->GetLines().GetObject( nLine );
+ nY += mnCharHeight;
+ if ( nY > rPosInPara.Y() ) // das war 'se
+ {
+ pLine = pTmpLine;
+ break; // richtige Y-Position intressiert nicht
+ }
+ }
+ DBG_ASSERT( pLine, "ImpFindIndex: pLine ?" );
+
+ nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X(), bSmart );
+
+ if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) &&
+ ( pLine != pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1) ) )
+ {
+ uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
+ sal_Int32 nCount = 1;
+ nCurIndex = (USHORT)xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
+ }
+ return nCurIndex;
+}
+
+USHORT TextEngine::GetCharPos( ULONG nPortion, USHORT nLine, long nXPos, BOOL )
+{
+
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
+ TextLine* pLine = pPortion->GetLines().GetObject( nLine );
+
+ USHORT nCurIndex = pLine->GetStart();
+
+ long nTmpX = pLine->GetStartX();
+ if ( nXPos <= nTmpX )
+ return nCurIndex;
+
+ for ( USHORT i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ )
+ {
+ TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( i );
+ nTmpX += pTextPortion->GetWidth();
+
+ if ( nTmpX > nXPos )
+ {
+ if( pTextPortion->GetLen() > 1 )
+ {
+ nTmpX -= pTextPortion->GetWidth(); // vor die Portion stellen
+ // Optimieren: Kein GetTextBreak, wenn feste Fontbreite...
+ Font aFont;
+ SeekCursor( nPortion, nCurIndex+1, aFont, NULL );
+ mpRefDev->SetFont( aFont);
+ long nPosInPortion = nXPos-nTmpX;
+ if ( IsRightToLeft() != pTextPortion->IsRightToLeft() )
+ nPosInPortion = pTextPortion->GetWidth() - nPosInPortion;
+ nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex );
+ // MT: GetTextBreak should assure that we are not withing a CTL cell...
+ }
+ return nCurIndex;
+ }
+ nCurIndex = nCurIndex + pTextPortion->GetLen();
+ }
+ return nCurIndex;
+}
+
+
+ULONG TextEngine::GetTextHeight() const
+{
+ DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: GetTextHeight" );
+
+ if ( !IsFormatted() && !IsFormatting() )
+ ((TextEngine*)this)->FormatAndUpdate();
+
+ return mnCurTextHeight;
+}
+
+ULONG TextEngine::GetTextHeight( ULONG nParagraph ) const
+{
+ DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: GetTextHeight" );
+
+ if ( !IsFormatted() && !IsFormatting() )
+ ((TextEngine*)this)->FormatAndUpdate();
+
+ return CalcParaHeight( nParagraph );
+}
+
+ULONG TextEngine::CalcTextWidth( ULONG nPara )
+{
+ ULONG nParaWidth = 0;
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
+ for ( USHORT nLine = pPortion->GetLines().Count(); nLine; )
+ {
+ ULONG nLineWidth = 0;
+ TextLine* pLine = pPortion->GetLines().GetObject( --nLine );
+ for ( USHORT nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
+ {
+ TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( nTP );
+ nLineWidth += pTextPortion->GetWidth();
+ }
+ if ( nLineWidth > nParaWidth )
+ nParaWidth = nLineWidth;
+ }
+ return nParaWidth;
+}
+
+ULONG TextEngine::CalcTextWidth()
+{
+ if ( !IsFormatted() && !IsFormatting() )
+ FormatAndUpdate();
+
+ if ( mnCurTextWidth == 0xFFFFFFFF )
+ {
+ mnCurTextWidth = 0;
+ for ( ULONG nPara = mpTEParaPortions->Count(); nPara; )
+ {
+ ULONG nParaWidth = CalcTextWidth( --nPara );
+ if ( nParaWidth > mnCurTextWidth )
+ mnCurTextWidth = nParaWidth;
+ }
+ }
+ return mnCurTextWidth+1;// Ein breiter, da in CreateLines bei >= umgebrochen wird.
+}
+
+ULONG TextEngine::CalcTextHeight()
+{
+ DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: CalcTextHeight" );
+
+ ULONG nY = 0;
+ for ( ULONG nPortion = mpTEParaPortions->Count(); nPortion; )
+ nY += CalcParaHeight( --nPortion );
+ return nY;
+}
+
+ULONG TextEngine::CalcTextWidth( ULONG nPara, USHORT nPortionStart, USHORT nLen, const Font* pFont )
+{
+ // Innerhalb des Textes darf es keinen Portionwechsel (Attribut/Tab) geben!
+ DBG_ASSERT( mpDoc->GetNodes().GetObject( nPara )->GetText().Search( '\t', nPortionStart ) >= (nPortionStart+nLen), "CalcTextWidth: Tab!" );
+
+ ULONG nWidth;
+ if ( mnFixCharWidth100 )
+ {
+ nWidth = (ULONG)nLen*mnFixCharWidth100/100;
+ }
+ else
+ {
+ if ( pFont )
+ {
+ if ( !mpRefDev->GetFont().IsSameInstance( *pFont ) )
+ mpRefDev->SetFont( *pFont );
+ }
+ else
+ {
+ Font aFont;
+ SeekCursor( nPara, nPortionStart+1, aFont, NULL );
+ mpRefDev->SetFont( aFont );
+ }
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ nWidth = (ULONG)mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen );
+
+ }
+ return nWidth;
+}
+
+
+USHORT TextEngine::GetLineCount( ULONG nParagraph ) const
+{
+ DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" );
+
+ TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
+ if ( pPPortion )
+ return pPPortion->GetLines().Count();
+
+ return 0xFFFF;
+}
+
+USHORT TextEngine::GetLineLen( ULONG nParagraph, USHORT nLine ) const
+{
+ DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" );
+
+ TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
+ if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) )
+ {
+ TextLine* pLine = pPPortion->GetLines().GetObject( nLine );
+ return pLine->GetLen();
+ }
+
+ return 0xFFFF;
+}
+
+ULONG TextEngine::CalcParaHeight( ULONG nParagraph ) const
+{
+ ULONG nHeight = 0;
+
+ TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
+ DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" );
+ if ( pPPortion )
+ nHeight = pPPortion->GetLines().Count() * mnCharHeight;
+
+ return nHeight;
+}
+
+void TextEngine::UpdateSelections()
+{
+}
+
+Range TextEngine::GetInvalidYOffsets( ULONG nPortion )
+{
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion );
+ USHORT nLines = pTEParaPortion->GetLines().Count();
+ USHORT nLastInvalid, nFirstInvalid = 0;
+ USHORT nLine;
+ for ( nLine = 0; nLine < nLines; nLine++ )
+ {
+ TextLine* pL = pTEParaPortion->GetLines().GetObject( nLine );
+ if ( pL->IsInvalid() )
+ {
+ nFirstInvalid = nLine;
+ break;
+ }
+ }
+
+ for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ )
+ {
+ TextLine* pL = pTEParaPortion->GetLines().GetObject( nLine );
+ if ( pL->IsValid() )
+ break;
+ }
+
+ if ( nLastInvalid >= nLines )
+ nLastInvalid = nLines-1;
+
+ return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 );
+}
+
+ULONG TextEngine::GetParagraphCount() const
+{
+ return mpDoc->GetNodes().Count();
+}
+
+void TextEngine::EnableUndo( BOOL bEnable )
+{
+ // Beim Umschalten des Modus Liste loeschen:
+ if ( bEnable != IsUndoEnabled() )
+ ResetUndo();
+
+ mbUndoEnabled = bEnable;
+}
+
+SfxUndoManager& TextEngine::GetUndoManager()
+{
+ if ( !mpUndoManager )
+ mpUndoManager = new TextUndoManager( this );
+ return *mpUndoManager;
+}
+
+void TextEngine::UndoActionStart( USHORT nId )
+{
+ if ( IsUndoEnabled() && !IsInUndo() )
+ {
+ String aComment;
+ // ...
+ GetUndoManager().EnterListAction( aComment, XubString(), nId );
+ }
+}
+
+void TextEngine::UndoActionEnd( USHORT )
+{
+ if ( IsUndoEnabled() && !IsInUndo() )
+ GetUndoManager().LeaveListAction();
+}
+
+void TextEngine::InsertUndo( TextUndo* pUndo, BOOL bTryMerge )
+{
+ DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" );
+ GetUndoManager().AddUndoAction( pUndo, bTryMerge );
+}
+
+void TextEngine::ResetUndo()
+{
+ if ( mpUndoManager )
+ mpUndoManager->Clear();
+}
+
+void TextEngine::InsertContent( TextNode* pNode, ULONG nPara )
+{
+ DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " );
+ DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" );
+ TEParaPortion* pNew = new TEParaPortion( pNode );
+ mpTEParaPortions->Insert( pNew, nPara );
+ mpDoc->GetNodes().Insert( pNode, nPara );
+ ImpParagraphInserted( nPara );
+}
+
+TextPaM TextEngine::SplitContent( ULONG nNode, USHORT nSepPos )
+{
+ #ifdef DBG_UTIL
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nNode );
+ DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" );
+ DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" );
+ DBG_ASSERT( nSepPos <= pNode->GetText().Len(), "Index im Wald: SplitContent" );
+ #endif
+ TextPaM aPaM( nNode, nSepPos );
+ return ImpInsertParaBreak( aPaM );
+}
+
+TextPaM TextEngine::ConnectContents( ULONG nLeftNode )
+{
+ DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" );
+ return ImpConnectParagraphs( nLeftNode, nLeftNode+1 );
+}
+
+void TextEngine::SeekCursor( ULONG nPara, USHORT nPos, Font& rFont, OutputDevice* pOutDev )
+{
+ rFont = maFont;
+ if ( pOutDev )
+ pOutDev->SetTextColor( maTextColor );
+
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ USHORT nAttribs = pNode->GetCharAttribs().Count();
+ for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr );
+ if ( pAttrib->GetStart() > nPos )
+ break;
+
+ // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen!
+ // Leere Attribute werden beruecksichtigt( verwendet), da diese
+ // gerade eingestellt wurden.
+ // 12.4.95: Doch keine Leeren Attribute verwenden:
+ // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font
+ // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam.
+ if ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) )
+ || !pNode->GetText().Len() )
+ {
+ if ( pAttrib->Which() != TEXTATTR_FONTCOLOR )
+ {
+ pAttrib->GetAttr().SetFont( rFont );
+ }
+ else
+ {
+ if ( pOutDev )
+ pOutDev->SetTextColor( ((TextAttribFontColor&)pAttrib->GetAttr()).GetColor() );
+ }
+ }
+ }
+
+ if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) &&
+ ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) )
+ {
+ sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ];
+ if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
+ rFont.SetUnderline( UNDERLINE_SINGLE );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
+ rFont.SetUnderline( UNDERLINE_BOLD );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
+ rFont.SetUnderline( UNDERLINE_DOTTED );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
+ rFont.SetUnderline( UNDERLINE_DOTTED );
+ if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
+ rFont.SetColor( Color( COL_RED ) );
+ else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
+ rFont.SetColor( Color( COL_LIGHTGRAY ) );
+ if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ rFont.SetColor( rStyleSettings.GetHighlightTextColor() );
+ rFont.SetFillColor( rStyleSettings.GetHighlightColor() );
+ rFont.SetTransparent( FALSE );
+ }
+ else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
+ {
+ rFont.SetUnderline( UNDERLINE_WAVE );
+// if( pOut )
+// pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) );
+ }
+ }
+}
+
+void TextEngine::SetUpdateMode( BOOL bUp, TextView* pCurView, BOOL bForceUpdate )
+{
+ BOOL bChanged = ( GetUpdateMode() != bUp );
+
+ mbUpdate = bUp;
+ if ( mbUpdate && ( bChanged || bForceUpdate ) )
+ FormatAndUpdate( pCurView );
+}
+
+void TextEngine::FormatAndUpdate( TextView* pCurView )
+{
+ if ( mbDowning )
+ return ;
+
+ if ( IsInUndo() )
+ IdleFormatAndUpdate( pCurView );
+ else
+ {
+ FormatDoc();
+ UpdateViews( pCurView );
+ }
+}
+
+
+void TextEngine::IdleFormatAndUpdate( TextView* pCurView, USHORT nMaxTimerRestarts )
+{
+ mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts );
+}
+
+void TextEngine::TextModified()
+{
+ mbFormatted = FALSE;
+ mbModified = TRUE;
+}
+
+void TextEngine::UpdateViews( TextView* pCurView )
+{
+ if ( !GetUpdateMode() || IsFormatting() || maInvalidRec.IsEmpty() )
+ return;
+
+ DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" );
+
+ for ( USHORT nView = 0; nView < mpViews->Count(); nView++ )
+ {
+ TextView* pView = mpViews->GetObject( nView );
+ pView->HideCursor();
+
+ Rectangle aClipRec( maInvalidRec );
+ Size aOutSz = pView->GetWindow()->GetOutputSizePixel();
+ Rectangle aVisArea( pView->GetStartDocPos(), aOutSz );
+ aClipRec.Intersection( aVisArea );
+ if ( !aClipRec.IsEmpty() )
+ {
+ // in Fensterkoordinaten umwandeln....
+ Point aNewPos = pView->GetWindowPos( aClipRec.TopLeft() );
+ if ( IsRightToLeft() )
+ aNewPos.X() -= aOutSz.Width() - 1;
+ aClipRec.SetPos( aNewPos );
+
+ if ( pView == pCurView )
+ pView->ImpPaint( aClipRec, !pView->GetWindow()->IsPaintTransparent() );
+ else
+ pView->GetWindow()->Invalidate( aClipRec );
+ }
+ }
+
+ if ( pCurView )
+ {
+ pCurView->ShowCursor( pCurView->IsAutoScroll() );
+ }
+
+ maInvalidRec = Rectangle();
+}
+
+IMPL_LINK( TextEngine, IdleFormatHdl, Timer *, EMPTYARG )
+{
+ FormatAndUpdate( mpIdleFormatter->GetView() );
+ return 0;
+}
+
+void TextEngine::CheckIdleFormatter()
+{
+ mpIdleFormatter->ForceTimeout();
+}
+
+void TextEngine::FormatFullDoc()
+{
+ for ( ULONG nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ )
+ {
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); USHORT nLen = pTEParaPortion->GetNode()->GetText().Len();
+ pTEParaPortion->MarkSelectionInvalid( 0, nLen );
+ }
+ mbFormatted = FALSE;
+ FormatDoc();
+}
+
+void TextEngine::FormatDoc()
+{
+ if ( IsFormatted() || !GetUpdateMode() || IsFormatting() )
+ return;
+
+ mbIsFormatting = TRUE;
+ mbHasMultiLineParas = FALSE;
+
+ long nY = 0;
+ BOOL bGrow = FALSE;
+
+ maInvalidRec = Rectangle(); // leermachen
+ for ( ULONG nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ )
+ {
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ if ( pTEParaPortion->IsInvalid() )
+ {
+ ULONG nOldParaWidth = 0xFFFFFFFF;
+ if ( mnCurTextWidth != 0xFFFFFFFF )
+ nOldParaWidth = CalcTextWidth( nPara );
+
+ ImpFormattingParagraph( nPara );
+
+ if ( CreateLines( nPara ) )
+ bGrow = TRUE;
+
+ // InvalidRec nur einmal setzen...
+ if ( maInvalidRec.IsEmpty() )
+ {
+ // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()...
+ long nWidth = (long)mnMaxTextWidth;
+ if ( !nWidth )
+ nWidth = 0x7FFFFFFF;
+ Range aInvRange( GetInvalidYOffsets( nPara ) );
+ maInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ),
+ Size( nWidth, aInvRange.Len() ) );
+ }
+ else
+ {
+ maInvalidRec.Bottom() = nY + CalcParaHeight( nPara );
+ }
+
+ if ( mnCurTextWidth != 0xFFFFFFFF )
+ {
+ ULONG nNewParaWidth = CalcTextWidth( nPara );
+ if ( nNewParaWidth >= mnCurTextWidth )
+ mnCurTextWidth = nNewParaWidth;
+ else if ( ( nOldParaWidth != 0xFFFFFFFF ) && ( nOldParaWidth >= mnCurTextWidth ) )
+ mnCurTextWidth = 0xFFFFFFFF;
+ }
+ }
+ else if ( bGrow )
+ {
+ maInvalidRec.Bottom() = nY + CalcParaHeight( nPara );
+ }
+ nY += CalcParaHeight( nPara );
+ if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().Count() > 1 )
+ mbHasMultiLineParas = TRUE;
+ }
+
+ if ( !maInvalidRec.IsEmpty() )
+ {
+ ULONG nNewHeight = CalcTextHeight();
+ long nDiff = nNewHeight - mnCurTextHeight;
+ if ( nNewHeight < mnCurTextHeight )
+ {
+ maInvalidRec.Bottom() = (long)Max( nNewHeight, mnCurTextHeight );
+ if ( maInvalidRec.IsEmpty() )
+ {
+ maInvalidRec.Top() = 0;
+ // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt.
+ maInvalidRec.Left() = 0;
+ maInvalidRec.Right() = mnMaxTextWidth;
+ }
+ }
+
+ mnCurTextHeight = nNewHeight;
+ if ( nDiff )
+ {
+ mbFormatted = TRUE;
+ ImpTextHeightChanged();
+ }
+ }
+
+ mbIsFormatting = FALSE;
+ mbFormatted = TRUE;
+
+ ImpTextFormatted();
+}
+
+void TextEngine::CreateAndInsertEmptyLine( ULONG nPara )
+{
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+
+ TextLine* pTmpLine = new TextLine;
+ pTmpLine->SetStart( pNode->GetText().Len() );
+ pTmpLine->SetEnd( pTmpLine->GetStart() );
+ pTEParaPortion->GetLines().Insert( pTmpLine, pTEParaPortion->GetLines().Count() );
+
+ if ( ImpGetAlign() == TXTALIGN_CENTER )
+ pTmpLine->SetStartX( (short)(mnMaxTextWidth / 2) );
+ else if ( ImpGetAlign() == TXTALIGN_RIGHT )
+ pTmpLine->SetStartX( (short)mnMaxTextWidth );
+ else
+ pTmpLine->SetStartX( mpDoc->GetLeftMargin() );
+
+ BOOL bLineBreak = pNode->GetText().Len() ? TRUE : FALSE;
+
+ TETextPortion* pDummyPortion = new TETextPortion( 0 );
+ pDummyPortion->GetWidth() = 0;
+ pTEParaPortion->GetTextPortions().Insert( pDummyPortion, pTEParaPortion->GetTextPortions().Count() );
+
+ if ( bLineBreak == TRUE )
+ {
+ // -2: Die neue ist bereits eingefuegt.
+ #ifdef DBG_UTIL
+ TextLine* pLastLine = pTEParaPortion->GetLines().GetObject( pTEParaPortion->GetLines().Count()-2 );
+ DBG_ASSERT( pLastLine, "Weicher Umbruch, keine Zeile ?!" );
+ #endif
+ USHORT nPos = (USHORT) pTEParaPortion->GetTextPortions().Count() - 1 ;
+ pTmpLine->SetStartPortion( nPos );
+ pTmpLine->SetEndPortion( nPos );
+ }
+}
+
+void TextEngine::ImpBreakLine( ULONG nPara, TextLine* pLine, TETextPortion*, USHORT nPortionStart, long nRemainingWidth )
+{
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+
+ // Font sollte noch eingestellt sein.
+ USHORT nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart );
+
+ DBG_ASSERT( nMaxBreakPos < pNode->GetText().Len(), "Break?!" );
+
+ if ( nMaxBreakPos == STRING_LEN ) // GetTextBreak() ist anderer Auffassung als GetTextSize()
+ nMaxBreakPos = pNode->GetText().Len() - 1;
+
+ uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
+ i18n::LineBreakHyphenationOptions aHyphOptions( NULL, uno::Sequence< beans::PropertyValue >(), 1 );
+
+ i18n::LineBreakUserOptions aUserOptions;
+ aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine;
+ aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine;
+ aUserOptions.applyForbiddenRules = sal_True;
+ aUserOptions.allowPunctuationOutsideMargin = sal_False;
+ aUserOptions.allowHyphenateEnglish = sal_False;
+
+ static const com::sun::star::lang::Locale aDefLocale;
+ i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions );
+ USHORT nBreakPos = (USHORT)aLBR.breakIndex;
+ if ( nBreakPos <= pLine->GetStart() )
+ {
+ nBreakPos = nMaxBreakPos;
+ if ( nBreakPos <= pLine->GetStart() )
+ nBreakPos = pLine->GetStart() + 1; // Sonst Endlosschleife!
+ }
+
+
+ // die angeknackste Portion ist die End-Portion
+ pLine->SetEnd( nBreakPos );
+ USHORT nEndPortion = SplitTextPortion( nPara, nBreakPos );
+
+ sal_Bool bBlankSeparator = ( ( nBreakPos >= pLine->GetStart() ) &&
+ ( pNode->GetText().GetChar( nBreakPos ) == ' ' ) ) ? sal_True : sal_False;
+ if ( bBlankSeparator )
+ {
+ // Blanks am Zeilenende generell unterdruecken...
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ TETextPortion* pTP = pTEParaPortion->GetTextPortions().GetObject( nEndPortion );
+ DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" );
+ pTP->GetWidth() = (long)CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 );
+ }
+ pLine->SetEndPortion( nEndPortion );
+}
+
+USHORT TextEngine::SplitTextPortion( ULONG nPara, USHORT nPos )
+{
+
+ // Die Portion bei nPos wird geplittet, wenn bei nPos nicht
+ // sowieso ein Wechsel ist
+ if ( nPos == 0 )
+ return 0;
+
+ USHORT nSplitPortion;
+ USHORT nTmpPos = 0;
+ TETextPortion* pTextPortion = 0;
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ USHORT nPortions = pTEParaPortion->GetTextPortions().Count();
+ for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ )
+ {
+ TETextPortion* pTP = pTEParaPortion->GetTextPortions().GetObject(nSplitPortion);
+ nTmpPos = nTmpPos + pTP->GetLen();
+ if ( nTmpPos >= nPos )
+ {
+ if ( nTmpPos == nPos ) // dann braucht nichts geteilt werden
+ return nSplitPortion;
+ pTextPortion = pTP;
+ break;
+ }
+ }
+
+ DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" );
+
+ USHORT nOverlapp = nTmpPos - nPos;
+ pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp;
+ TETextPortion* pNewPortion = new TETextPortion( nOverlapp );
+ pTEParaPortion->GetTextPortions().Insert( pNewPortion, nSplitPortion+1 );
+ pTextPortion->GetWidth() = (long)CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() );
+
+ return nSplitPortion;
+}
+
+void TextEngine::CreateTextPortions( ULONG nPara, USHORT nStartPos )
+{
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ TextNode* pNode = pTEParaPortion->GetNode();
+ DBG_ASSERT( pNode->GetText().Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" );
+
+ TESortedPositions aPositions;
+ ULONG nZero = 0;
+ aPositions.Insert( nZero );
+
+ USHORT nAttribs = pNode->GetCharAttribs().Count();
+ for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr );
+
+ // Start und Ende in das Array eintragen...
+ // Die InsertMethode laesst keine doppelten Werte zu....
+ aPositions.Insert( pAttrib->GetStart() );
+ aPositions.Insert( pAttrib->GetEnd() );
+ }
+ aPositions.Insert( pNode->GetText().Len() );
+
+ const TEWritingDirectionInfos& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos();
+ for ( USHORT nD = 0; nD < rWritingDirections.Count(); nD++ )
+ aPositions.Insert( rWritingDirections[nD].nStartPos );
+
+ if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) )
+ {
+ sal_uInt16 nLastAttr = 0xFFFF;
+ for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ )
+ {
+ if ( mpIMEInfos->pAttribs[n] != nLastAttr )
+ {
+ aPositions.Insert( mpIMEInfos->aPos.GetIndex() + n );
+ nLastAttr = mpIMEInfos->pAttribs[n];
+ }
+ }
+ }
+
+ USHORT nTabPos = pNode->GetText().Search( '\t', 0 );
+ while ( nTabPos != STRING_NOTFOUND )
+ {
+ aPositions.Insert( nTabPos );
+ aPositions.Insert( nTabPos + 1 );
+ nTabPos = pNode->GetText().Search( '\t', nTabPos+1 );
+ }
+
+ // Ab ... loeschen:
+ // Leider muss die Anzahl der TextPortions mit aPositions.Count()
+ // nicht uebereinstimmen, da evtl. Zeilenumbrueche...
+ USHORT nPortionStart = 0;
+ USHORT nInvPortion = 0;
+ USHORT nP;
+ for ( nP = 0; nP < pTEParaPortion->GetTextPortions().Count(); nP++ )
+ {
+ TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions().GetObject(nP);
+ nPortionStart = nPortionStart + pTmpPortion->GetLen();
+ if ( nPortionStart >= nStartPos )
+ {
+ nPortionStart = nPortionStart - pTmpPortion->GetLen();
+ nInvPortion = nP;
+ break;
+ }
+ }
+ DBG_ASSERT( nP < pTEParaPortion->GetTextPortions().Count() || !pTEParaPortion->GetTextPortions().Count(), "Nichts zum loeschen: CreateTextPortions" );
+ if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen() > nStartPos ) )
+ {
+ // lieber eine davor...
+ // Aber nur wenn es mitten in der Portion war, sonst ist es evtl.
+ // die einzige in der Zeile davor !
+ nInvPortion--;
+ nPortionStart = nPortionStart - pTEParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen();
+ }
+ pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion );
+
+ // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein:
+ aPositions.Insert( nPortionStart );
+
+ USHORT nInvPos;
+ #ifdef DBG_UTIL
+ BOOL bFound =
+ #endif
+ aPositions.Seek_Entry( nPortionStart, &nInvPos );
+ DBG_ASSERT( bFound && ( nInvPos < (aPositions.Count()-1) ), "InvPos ?!" );
+ for ( USHORT i = nInvPos+1; i < aPositions.Count(); i++ )
+ {
+ TETextPortion* pNew = new TETextPortion( (USHORT)aPositions[i] - (USHORT)aPositions[i-1] );
+ pTEParaPortion->GetTextPortions().Insert( pNew, pTEParaPortion->GetTextPortions().Count());
+ }
+
+ DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "Keine Portions?!" );
+#ifdef EDITDEBUG
+ DBG_ASSERT( pTEParaPortion->DbgCheckTextPortions(), "Portions kaputt?" );
+#endif
+}
+
+void TextEngine::RecalcTextPortion( ULONG nPara, USHORT nStartPos, short nNewChars )
+{
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "Keine Portions!" );
+ DBG_ASSERT( nNewChars, "RecalcTextPortion mit Diff == 0" );
+
+ TextNode* const pNode = pTEParaPortion->GetNode();
+ if ( nNewChars > 0 )
+ {
+ // Wenn an nStartPos ein Attribut beginnt/endet, oder vor nStartPos
+ // ein Tab steht, faengt eine neue Portion an,
+ // ansonsten wird die Portion an nStartPos erweitert.
+ // Oder wenn ganz vorne ( StartPos 0 ) und dann ein Tab
+
+ if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) ||
+ ( nStartPos && ( pNode->GetText().GetChar( nStartPos - 1 ) == '\t' ) ) ||
+ ( ( !nStartPos && ( nNewChars < pNode->GetText().Len() ) && pNode->GetText().GetChar( nNewChars ) == '\t' ) ) )
+ {
+ USHORT nNewPortionPos = 0;
+ if ( nStartPos )
+ nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1;
+// else if ( ( pTEParaPortion->GetTextPortions().Count() == 1 ) &&
+// !pTEParaPortion->GetTextPortions()[0]->GetLen() )
+// pTEParaPortion->GetTextPortions().Reset(); // DummyPortion
+
+ // Eine leere Portion kann hier stehen, wenn der Absatz leer war,
+ // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist.
+ if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().Count() ) &&
+ !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() )
+ {
+ // Dann die leere Portion verwenden.
+ USHORT & r =
+ pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen();
+ r = r + nNewChars;
+ }
+ else
+ {
+ TETextPortion* pNewPortion = new TETextPortion( nNewChars );
+ pTEParaPortion->GetTextPortions().Insert( pNewPortion, nNewPortionPos );
+ }
+ }
+ else
+ {
+ USHORT nPortionStart;
+ const USHORT nTP = pTEParaPortion->GetTextPortions().
+ FindPortion( nStartPos, nPortionStart );
+ TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ];
+ DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" );
+ pTP->GetLen() = pTP->GetLen() + nNewChars;
+ pTP->GetWidth() = (-1);
+ }
+ }
+ else
+ {
+ // Portion schrumpfen oder ggf. entfernen.
+ // Vor Aufruf dieser Methode muss sichergestellt sein, dass
+ // keine Portions in dem geloeschten Bereich lagen!
+
+ // Es darf keine reinragende oder im Bereich startende Portion geben,
+ // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein
+ USHORT nPortion = 0;
+ USHORT nPos = 0;
+ USHORT nEnd = nStartPos-nNewChars;
+ USHORT nPortions = pTEParaPortion->GetTextPortions().Count();
+ TETextPortion* pTP = 0;
+ for ( nPortion = 0; nPortion < nPortions; nPortion++ )
+ {
+ pTP = pTEParaPortion->GetTextPortions()[ nPortion ];
+ if ( ( nPos+pTP->GetLen() ) > nStartPos )
+ {
+ DBG_ASSERT( nPos <= nStartPos, "Start falsch!" );
+ DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" );
+ break;
+ }
+ nPos = nPos + pTP->GetLen();
+ }
+ DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" );
+ if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) )
+ {
+ // Portion entfernen;
+ pTEParaPortion->GetTextPortions().Remove( nPortion );
+ delete pTP;
+ }
+ else
+ {
+ DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" );
+ pTP->GetLen() = pTP->GetLen() + nNewChars;
+ }
+ DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "RecalcTextPortions: Keine mehr da!" );
+ }
+
+#ifdef EDITDEBUG
+ DBG_ASSERT( pTEParaPortion->DbgCheckTextPortions(), "Portions kaputt?" );
+#endif
+}
+
+void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection )
+{
+ if ( !GetUpdateMode() )
+ return;
+
+ if ( !IsFormatted() )
+ FormatDoc();
+
+ bool bTransparent = false;
+ Window* pOutWin = dynamic_cast<Window*>(pOutDev);
+ bTransparent = (pOutWin && pOutWin->IsPaintTransparent());
+
+ long nY = rStartPos.Y();
+
+ TextPaM const* pSelStart = 0;
+ TextPaM const* pSelEnd = 0;
+ if ( pSelection && pSelection->HasRange() )
+ {
+ BOOL bInvers = pSelection->GetEnd() < pSelection->GetStart();
+ pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd();
+ pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd();
+ }
+ DBG_ASSERT( !pPaintRange || ( pPaintRange->GetStart() < pPaintRange->GetEnd() ), "ImpPaint: Paint-Range?!" );
+
+ const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
+
+ // --------------------------------------------------
+ // Ueber alle Absaetze...
+ // --------------------------------------------------
+ for ( ULONG nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ )
+ {
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
+ // falls beim Tippen Idle-Formatierung, asynchrones Paint.
+ if ( pPortion->IsInvalid() )
+ return;
+
+ ULONG nParaHeight = CalcParaHeight( nPara );
+ USHORT nIndex = 0;
+ if ( ( !pPaintArea || ( ( nY + (long)nParaHeight ) > pPaintArea->Top() ) )
+ && ( !pPaintRange || ( ( nPara >= pPaintRange->GetStart().GetPara() ) && ( nPara <= pPaintRange->GetEnd().GetPara() ) ) ) )
+ {
+ // --------------------------------------------------
+ // Ueber die Zeilen des Absatzes...
+ // --------------------------------------------------
+ USHORT nLines = pPortion->GetLines().Count();
+ for ( USHORT nLine = 0; nLine < nLines; nLine++ )
+ {
+ TextLine* pLine = pPortion->GetLines().GetObject(nLine);
+ Point aTmpPos( rStartPos.X() + pLine->GetStartX(), nY );
+
+ if ( ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) )
+ && ( !pPaintRange || (
+ ( TextPaM( nPara, pLine->GetStart() ) < pPaintRange->GetEnd() ) &&
+ ( TextPaM( nPara, pLine->GetEnd() ) > pPaintRange->GetStart() ) ) ) )
+ {
+ // --------------------------------------------------
+ // Ueber die Portions der Zeile...
+ // --------------------------------------------------
+ nIndex = pLine->GetStart();
+ for ( USHORT y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ )
+ {
+ DBG_ASSERT( pPortion->GetTextPortions().Count(), "Zeile ohne Textportion im Paint!" );
+ TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( y );
+ DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" );
+
+ ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */);
+
+ long nTxtWidth = pTextPortion->GetWidth();
+ aTmpPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nIndex, nIndex );
+
+ // nur ausgeben, was im sichtbaren Bereich beginnt:
+ if ( ( ( aTmpPos.X() + nTxtWidth ) >= 0 )
+ && ( !pPaintRange || (
+ ( TextPaM( nPara, nIndex ) < pPaintRange->GetEnd() ) &&
+ ( TextPaM( nPara, nIndex + pTextPortion->GetLen() ) > pPaintRange->GetStart() ) ) ) )
+ {
+ switch ( pTextPortion->GetKind() )
+ {
+ case PORTIONKIND_TEXT:
+ {
+ {
+ Font aFont;
+ SeekCursor( nPara, nIndex+1, aFont, pOutDev );
+ if( bTransparent )
+ aFont.SetTransparent( TRUE );
+ else if ( pSelection )
+ aFont.SetTransparent( FALSE );
+ pOutDev->SetFont( aFont );
+
+ USHORT nTmpIndex = nIndex;
+ USHORT nEnd = nTmpIndex + pTextPortion->GetLen();
+ Point aPos = aTmpPos;
+ if ( pPaintRange )
+ {
+ // evtl soll nicht alles ausgegeben werden...
+ if ( ( pPaintRange->GetStart().GetPara() == nPara )
+ && ( nTmpIndex < pPaintRange->GetStart().GetIndex() ) )
+ {
+ nTmpIndex = pPaintRange->GetStart().GetIndex();
+ }
+ if ( ( pPaintRange->GetEnd().GetPara() == nPara )
+ && ( nEnd > pPaintRange->GetEnd().GetIndex() ) )
+ {
+ nEnd = pPaintRange->GetEnd().GetIndex();
+ }
+ }
+
+ BOOL bDone = FALSE;
+ if ( pSelStart )
+ {
+ // liegt ein Teil in der Selektion???
+ TextPaM aTextStart( nPara, nTmpIndex );
+ TextPaM aTextEnd( nPara, nEnd );
+ if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) )
+ {
+ USHORT nL;
+
+ // 1) Bereich vor Selektion
+ if ( aTextStart < *pSelStart )
+ {
+ nL = pSelStart->GetIndex() - nTmpIndex;
+ pOutDev->SetFont( aFont);
+ aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL );
+ pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL );
+ nTmpIndex = nTmpIndex + nL;
+
+ }
+ // 2) Bereich mit Selektion
+ nL = nEnd-nTmpIndex;
+ if ( aTextEnd > *pSelEnd )
+ nL = pSelEnd->GetIndex() - nTmpIndex;
+ if ( nL )
+ {
+ Color aOldTextColor = pOutDev->GetTextColor();
+ pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() );
+ pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() );
+ aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL );
+ pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL );
+ pOutDev->SetTextColor( aOldTextColor );
+ pOutDev->SetTextFillColor();
+ nTmpIndex = nTmpIndex + nL;
+ }
+
+ // 3) Bereich nach Selektion
+ if ( nTmpIndex < nEnd )
+ {
+ nL = nEnd-nTmpIndex;
+ aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL );
+ pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex );
+ }
+ bDone = TRUE;
+ }
+ }
+ if ( !bDone )
+ {
+ aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nEnd );
+ pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex );
+ }
+ }
+
+ }
+ break;
+ case PORTIONKIND_TAB:
+ {
+ // Bei HideSelection() nur Range, pSelection = 0.
+ if ( pSelStart || pPaintRange )
+ {
+ Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) );
+ BOOL bDone = FALSE;
+ if ( pSelStart )
+ {
+ // liegt der Tab in der Selektion???
+ TextPaM aTextStart( nPara, nIndex );
+ TextPaM aTextEnd( nPara, nIndex+1 );
+ if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) )
+ {
+ Color aOldColor = pOutDev->GetFillColor();
+ pOutDev->SetFillColor( rStyleSettings.GetHighlightColor() );
+ pOutDev->DrawRect( aTabArea );
+ pOutDev->SetFillColor( aOldColor );
+ bDone = TRUE;
+ }
+ }
+ if ( !bDone )
+ {
+ pOutDev->Erase( aTabArea );
+ }
+ }
+#ifdef EDITDEBUG
+ Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) );
+ Color aOldColor = pOutDev->GetFillColor();
+ pOutDev->SetFillColor( (y%2) ? COL_RED : COL_GREEN );
+ pOutDev->DrawRect( aTabArea );
+ pOutDev->SetFillColor( aOldColor );
+#endif
+ }
+ break;
+ default: DBG_ERROR( "ImpPaint: Unknown Portion-Type !" );
+ }
+ }
+
+ nIndex = nIndex + pTextPortion->GetLen();
+ }
+ }
+
+ nY += mnCharHeight;
+
+ if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) )
+ break; // keine sichtbaren Aktionen mehr...
+ }
+ }
+ else
+ {
+ nY += nParaHeight;
+ }
+
+ if ( pPaintArea && ( nY > pPaintArea->Bottom() ) )
+ break; // keine sichtbaren Aktionen mehr...
+ }
+}
+
+BOOL TextEngine::CreateLines( ULONG nPara )
+{
+ // BOOL: Aenderung der Hoehe des Absatzes Ja/Nein - TRUE/FALSE
+
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ DBG_ASSERT( pTEParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" );
+
+ USHORT nOldLineCount = pTEParaPortion->GetLines().Count();
+
+ // ---------------------------------------------------------------
+ // Schnelle Sonderbehandlung fuer leere Absaetze...
+ // ---------------------------------------------------------------
+ if ( pTEParaPortion->GetNode()->GetText().Len() == 0 )
+ {
+ // schnelle Sonderbehandlung...
+ if ( pTEParaPortion->GetTextPortions().Count() )
+ pTEParaPortion->GetTextPortions().Reset();
+ if ( pTEParaPortion->GetLines().Count() )
+ pTEParaPortion->GetLines().DeleteAndDestroy( 0, pTEParaPortion->GetLines().Count() );
+ CreateAndInsertEmptyLine( nPara );
+ pTEParaPortion->SetValid();
+ return nOldLineCount != pTEParaPortion->GetLines().Count();
+ }
+
+ // ---------------------------------------------------------------
+ // Initialisierung......
+ // ---------------------------------------------------------------
+
+ if ( pTEParaPortion->GetLines().Count() == 0 )
+ {
+ TextLine* pL = new TextLine;
+ pTEParaPortion->GetLines().Insert( pL, 0 );
+ }
+
+ const short nInvalidDiff = pTEParaPortion->GetInvalidDiff();
+ const USHORT nInvalidStart = pTEParaPortion->GetInvalidPosStart();
+ const USHORT nInvalidEnd = nInvalidStart + Abs( nInvalidDiff );
+ BOOL bQuickFormat = FALSE;
+
+ if ( !pTEParaPortion->GetWritingDirectionInfos().Count() )
+ ImpInitWritingDirections( nPara );
+
+ if ( pTEParaPortion->GetWritingDirectionInfos().Count() == 1 )
+ {
+ if ( pTEParaPortion->IsSimpleInvalid() && ( nInvalidDiff > 0 ) )
+ {
+ bQuickFormat = TRUE;
+ }
+ else if ( ( pTEParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
+ {
+ // pruefen, ob loeschen ueber Portiongrenzen erfolgte...
+ USHORT nStart = nInvalidStart; // DOPPELT !!!!!!!!!!!!!!!
+ USHORT nEnd = nStart - nInvalidDiff; // neg.
+ bQuickFormat = TRUE;
+ USHORT nPos = 0;
+ USHORT nPortions = pTEParaPortion->GetTextPortions().Count();
+ for ( USHORT nTP = 0; nTP < nPortions; nTP++ )
+ {
+ // Es darf kein Start/Ende im geloeschten Bereich liegen.
+ TETextPortion* const pTP = pTEParaPortion->GetTextPortions().GetObject( nTP );
+ nPos = nPos + pTP->GetLen();
+ if ( ( nPos > nStart ) && ( nPos < nEnd ) )
+ {
+ bQuickFormat = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( bQuickFormat )
+ RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff );
+ else
+ CreateTextPortions( nPara, nInvalidStart );
+
+ // ---------------------------------------------------------------
+ // Zeile mit InvalidPos suchen, eine Zeile davor beginnen...
+ // Zeilen flaggen => nicht removen !
+ // ---------------------------------------------------------------
+
+ USHORT nLine = pTEParaPortion->GetLines().Count()-1;
+ for ( USHORT nL = 0; nL <= nLine; nL++ )
+ {
+ TextLine* pLine = pTEParaPortion->GetLines().GetObject( nL );
+ if ( pLine->GetEnd() > nInvalidStart )
+ {
+ nLine = nL;
+ break;
+ }
+ pLine->SetValid();
+ }
+ // Eine Zeile davor beginnen...
+ // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern.
+ if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().Len() ) || ( nInvalidDiff <= 0 ) ) )
+ nLine--;
+
+ TextLine* pLine = pTEParaPortion->GetLines().GetObject( nLine );
+
+ // ---------------------------------------------------------------
+ // Ab hier alle Zeilen durchformatieren...
+ // ---------------------------------------------------------------
+ USHORT nDelFromLine = 0xFFFF;
+ BOOL bLineBreak = FALSE;
+
+ USHORT nIndex = pLine->GetStart();
+ TextLine aSaveLine( *pLine );
+
+ Font aFont;
+
+ BOOL bCalcPortion = TRUE;
+
+ while ( nIndex < pNode->GetText().Len() )
+ {
+ BOOL bEOL = FALSE;
+ BOOL bEOC = FALSE;
+ USHORT nPortionStart = 0;
+ USHORT nPortionEnd = 0;
+
+ USHORT nTmpPos = nIndex;
+ USHORT nTmpPortion = pLine->GetStartPortion();
+ long nTmpWidth = mpDoc->GetLeftMargin();
+// long nXWidth = mnMaxTextWidth ? ( mnMaxTextWidth - mpDoc->GetLeftMargin() ) : 0x7FFFFFFF;
+ // Margin nicht abziehen, ist schon in TmpWidth enthalten.
+ long nXWidth = mnMaxTextWidth ? mnMaxTextWidth : 0x7FFFFFFF;
+ if ( nXWidth < nTmpWidth )
+ nXWidth = nTmpWidth;
+
+ // Portion suchen, die nicht mehr in Zeile passt....
+ TETextPortion* pPortion = 0;
+ BOOL bBrokenLine = FALSE;
+ bLineBreak = FALSE;
+
+ while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().Count() ) )
+ {
+ nPortionStart = nTmpPos;
+ pPortion = pTEParaPortion->GetTextPortions().GetObject( nTmpPortion );
+ DBG_ASSERT( pPortion->GetLen(), "Leere Portion in CreateLines ?!" );
+ if ( pNode->GetText().GetChar( nTmpPos ) == '\t' )
+ {
+ long nCurPos = nTmpWidth-mpDoc->GetLeftMargin();
+ nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin();
+ pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin();
+ // Wenn dies das erste Token in der Zeile ist, und
+ // nTmpWidth > aPaperSize.Width, habe ich eine Endlos-Schleife!
+ if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
+ {
+ // Aber was jetzt ? Tab passend machen!
+ pPortion->GetWidth() = nXWidth-1;
+ nTmpWidth = pPortion->GetWidth();
+ bEOL = TRUE;
+ bBrokenLine = TRUE;
+ }
+ pPortion->GetKind() = PORTIONKIND_TAB;
+ }
+ else
+ {
+
+ if ( bCalcPortion || !pPortion->HasValidSize() )
+ pPortion->GetWidth() = (long)CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() );
+ nTmpWidth += pPortion->GetWidth();
+
+ pPortion->GetRightToLeft() = ImpGetRightToLeft( nPara, nTmpPos+1 );
+ pPortion->GetKind() = PORTIONKIND_TEXT;
+ }
+
+ nTmpPos = nTmpPos + pPortion->GetLen();
+ nPortionEnd = nTmpPos;
+ nTmpPortion++;
+ }
+
+ // das war evtl. eine Portion zu weit:
+ BOOL bFixedEnd = FALSE;
+ if ( nTmpWidth > nXWidth )
+ {
+ nPortionEnd = nTmpPos;
+ nTmpPos = nTmpPos - pPortion->GetLen();
+ nPortionStart = nTmpPos;
+ nTmpPortion--;
+ bEOL = FALSE;
+ bEOC = FALSE;
+
+ nTmpWidth -= pPortion->GetWidth();
+ if ( pPortion->GetKind() == PORTIONKIND_TAB )
+ {
+ bEOL = TRUE;
+ bFixedEnd = TRUE;
+ }
+ }
+ else
+ {
+ bEOL = TRUE;
+ bEOC = TRUE;
+ pLine->SetEnd( nPortionEnd );
+ DBG_ASSERT( pTEParaPortion->GetTextPortions().Count(), "Keine TextPortions?" );
+ pLine->SetEndPortion( (USHORT)pTEParaPortion->GetTextPortions().Count() - 1 );
+ }
+
+ if ( bFixedEnd )
+ {
+ pLine->SetEnd( nPortionStart );
+ pLine->SetEndPortion( nTmpPortion-1 );
+ }
+ else if ( bLineBreak || bBrokenLine )
+ {
+ pLine->SetEnd( nPortionStart+1 );
+ pLine->SetEndPortion( nTmpPortion-1 );
+ bEOC = FALSE; // wurde oben gesetzt, vielleich mal die if's umstellen?
+ }
+ else if ( !bEOL )
+ {
+ DBG_ASSERT( (nPortionEnd-nPortionStart) == pPortion->GetLen(), "Doch eine andere Portion?!" );
+ long nRemainingWidth = mnMaxTextWidth - nTmpWidth;
+ ImpBreakLine( nPara, pLine, pPortion, nPortionStart, nRemainingWidth );
+ }
+
+ if ( ( ImpGetAlign() == TXTALIGN_CENTER ) || ( ImpGetAlign() == TXTALIGN_RIGHT ) )
+ {
+ // Ausrichten...
+ long nTextWidth = 0;
+ for ( USHORT nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
+ {
+ TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions().GetObject( nTP );
+ nTextWidth += pTextPortion->GetWidth();
+ }
+ long nSpace = mnMaxTextWidth - nTextWidth;
+ if ( nSpace > 0 )
+ {
+ if ( ImpGetAlign() == TXTALIGN_CENTER )
+ pLine->SetStartX( (USHORT)(nSpace / 2) );
+ else // TXTALIGN_RIGHT
+ pLine->SetStartX( (USHORT)nSpace );
+ }
+ }
+ else
+ {
+ pLine->SetStartX( mpDoc->GetLeftMargin() );
+ }
+
+ // -----------------------------------------------------------------
+ // pruefen, ob die Zeile neu ausgegeben werden muss...
+ // -----------------------------------------------------------------
+ pLine->SetInvalid();
+
+ if ( pTEParaPortion->IsSimpleInvalid() )
+ {
+ // Aenderung durch einfache Textaenderung...
+ // Formatierung nicht abbrechen, da Portions evtl. wieder
+ // gesplittet werden muessen!
+ // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren!
+ // Aber ggf. als Valid markieren, damit weniger Ausgabe...
+ if ( pLine->GetEnd() < nInvalidStart )
+ {
+ if ( *pLine == aSaveLine )
+ {
+ pLine->SetValid();
+ }
+ }
+ else
+ {
+ USHORT nStart = pLine->GetStart();
+ USHORT nEnd = pLine->GetEnd();
+
+ if ( nStart > nInvalidEnd )
+ {
+ if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) &&
+ ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) )
+ {
+ pLine->SetValid();
+ if ( bCalcPortion && bQuickFormat )
+ {
+ bCalcPortion = FALSE;
+ pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
+ break;
+ }
+ }
+ }
+ else if ( bQuickFormat && ( nEnd > nInvalidEnd) )
+ {
+ // Wenn die ungueltige Zeile so endet, dass die naechste an
+ // der 'gleichen' Textstelle wie vorher beginnt, also nicht
+ // anders umgebrochen wird, brauche ich dort auch nicht die
+ // textbreiten neu bestimmen:
+ if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) )
+ {
+ bCalcPortion = FALSE;
+ pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
+ break;
+ }
+ }
+ }
+ }
+
+ nIndex = pLine->GetEnd(); // naechste Zeile Start = letzte Zeile Ende
+ // weil nEnd hinter das letzte Zeichen zeigt!
+
+ USHORT nEndPortion = pLine->GetEndPortion();
+
+ // Naechste Zeile oder ggf. neue Zeile....
+ pLine = 0;
+ if ( nLine < pTEParaPortion->GetLines().Count()-1 )
+ pLine = pTEParaPortion->GetLines().GetObject( ++nLine );
+ if ( pLine && ( nIndex >= pNode->GetText().Len() ) )
+ {
+ nDelFromLine = nLine;
+ break;
+ }
+ if ( !pLine && ( nIndex < pNode->GetText().Len() ) )
+ {
+ pLine = new TextLine;
+ pTEParaPortion->GetLines().Insert( pLine, ++nLine );
+ }
+ if ( pLine )
+ {
+ aSaveLine = *pLine;
+ pLine->SetStart( nIndex );
+ pLine->SetEnd( nIndex );
+ pLine->SetStartPortion( nEndPortion+1 );
+ pLine->SetEndPortion( nEndPortion+1 );
+ }
+ } // while ( Index < Len )
+
+ if ( nDelFromLine != 0xFFFF )
+ pTEParaPortion->GetLines().DeleteAndDestroy( nDelFromLine, pTEParaPortion->GetLines().Count() - nDelFromLine );
+
+ DBG_ASSERT( pTEParaPortion->GetLines().Count(), "Keine Zeile nach CreateLines!" );
+
+ if ( bLineBreak == TRUE )
+ CreateAndInsertEmptyLine( nPara );
+
+ pTEParaPortion->SetValid();
+
+ return nOldLineCount != pTEParaPortion->GetLines().Count();
+}
+
+String TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord )
+{
+ String aWord;
+ if ( rCursorPos.GetPara() < mpDoc->GetNodes().Count() )
+ {
+ TextSelection aSel( rCursorPos );
+ TextNode* pNode = mpDoc->GetNodes().GetObject( rCursorPos.GetPara() );
+ uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
+ i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
+ aSel.GetStart().GetIndex() = (USHORT)aBoundary.startPos;
+ aSel.GetEnd().GetIndex() = (USHORT)aBoundary.endPos;
+ aWord = pNode->GetText().Copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() );
+ if ( pStartOfWord )
+ *pStartOfWord = aSel.GetStart();
+ }
+ return aWord;
+}
+
+BOOL TextEngine::Read( SvStream& rInput, const TextSelection* pSel )
+{
+ BOOL bUpdate = GetUpdateMode();
+ SetUpdateMode( FALSE );
+
+ UndoActionStart( TEXTUNDO_READ );
+ TextSelection aSel;
+ if ( pSel )
+ aSel = *pSel;
+ else
+ {
+ ULONG nParas = mpDoc->GetNodes().Count();
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 );
+ aSel = TextPaM( nParas-1 , pNode->GetText().Len() );
+ }
+
+ if ( aSel.HasRange() )
+ aSel = ImpDeleteText( aSel );
+
+ ByteString aLine;
+ BOOL bDone = rInput.ReadLine( aLine );
+ String aTmpStr( aLine, rInput.GetStreamCharSet() ), aStr;
+ while ( bDone )
+ {
+ aSel = ImpInsertText( aSel, aTmpStr );
+ bDone = rInput.ReadLine( aLine );
+ aTmpStr = String( aLine, rInput.GetStreamCharSet() );
+ if ( bDone )
+ aSel = ImpInsertParaBreak( aSel.GetEnd() );
+ }
+
+ UndoActionEnd( TEXTUNDO_READ );
+
+ TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() );
+
+ // Damit bei FormatAndUpdate nicht auf die ungueltige Selektion zugegriffen wird.
+ if ( GetActiveView() )
+ GetActiveView()->ImpSetSelection( aNewSel );
+
+ SetUpdateMode( bUpdate );
+ FormatAndUpdate( GetActiveView() );
+
+ return rInput.GetError() ? FALSE : TRUE;
+}
+
+BOOL TextEngine::Write( SvStream& rOutput, const TextSelection* pSel, BOOL bHTML )
+{
+ TextSelection aSel;
+ if ( pSel )
+ aSel = *pSel;
+ else
+ {
+ ULONG nParas = mpDoc->GetNodes().Count();
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 );
+ aSel.GetStart() = TextPaM( 0, 0 );
+ aSel.GetEnd() = TextPaM( nParas-1, pNode->GetText().Len() );
+ }
+
+ if ( bHTML )
+ {
+ rOutput.WriteLine( "<HTML>" );
+ rOutput.WriteLine( "<BODY>" );
+ }
+
+ for ( ULONG nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); nPara++ )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+
+ USHORT nStartPos = 0;
+ USHORT nEndPos = pNode->GetText().Len();
+ if ( nPara == aSel.GetStart().GetPara() )
+ nStartPos = aSel.GetStart().GetIndex();
+ if ( nPara == aSel.GetEnd().GetPara() )
+ nEndPos = aSel.GetEnd().GetIndex();
+
+ String aText;
+ if ( !bHTML )
+ {
+ aText = pNode->GetText().Copy( nStartPos, nEndPos-nStartPos );
+ }
+ else
+ {
+ aText.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "<P STYLE=\"margin-bottom: 0cm\">" ) );
+
+ if ( nStartPos == nEndPos )
+ {
+ // Leerzeilen werden von Writer wegoptimiert
+ aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "<BR>" ) );
+ }
+ else
+ {
+ USHORT nTmpStart = nStartPos;
+ USHORT nTmpEnd = nEndPos;
+ do
+ {
+ TextCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( TEXTATTR_HYPERLINK, nTmpStart, nEndPos );
+ nTmpEnd = pAttr ? pAttr->GetStart() : nEndPos;
+
+ // Text vor dem Attribut
+ aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart );
+
+ if ( pAttr )
+ {
+ nTmpEnd = Min( pAttr->GetEnd(), nEndPos );
+
+ // z.B. <A HREF="http://www.mopo.de/">Morgenpost</A>
+ aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "<A HREF=\"" ) );
+ aText += ((const TextAttribHyperLink&) pAttr->GetAttr() ).GetURL();
+ aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "\">" ) );
+ nTmpStart = pAttr->GetStart();
+ aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart );
+ aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "</A>" ) );
+
+ nTmpStart = pAttr->GetEnd();
+ }
+ } while ( nTmpEnd < nEndPos );
+ }
+
+ aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "</P>" ) );
+ }
+ rOutput.WriteLine( ByteString( aText, rOutput.GetStreamCharSet() ) );
+ }
+
+ if ( bHTML )
+ {
+ rOutput.WriteLine( "</BODY>" );
+ rOutput.WriteLine( "</HTML>" );
+ }
+
+ return rOutput.GetError() ? FALSE : TRUE;
+}
+
+void TextEngine::RemoveAttribs( ULONG nPara, BOOL bIdleFormatAndUpdate )
+{
+ if ( nPara < mpDoc->GetNodes().Count() )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ if ( pNode->GetCharAttribs().Count() )
+ {
+ pNode->GetCharAttribs().Clear( TRUE );
+
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() );
+
+ mbFormatted = FALSE;
+
+ if ( bIdleFormatAndUpdate )
+ IdleFormatAndUpdate( NULL, 0xFFFF );
+ else
+ FormatAndUpdate( NULL );
+ }
+ }
+}
+void TextEngine::RemoveAttribs( ULONG nPara, USHORT nWhich, BOOL bIdleFormatAndUpdate )
+{
+ if ( nPara < mpDoc->GetNodes().Count() )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ if ( pNode->GetCharAttribs().Count() )
+ {
+ TextCharAttribList& rAttribs = pNode->GetCharAttribs();
+ USHORT nAttrCount = rAttribs.Count();
+ for(USHORT nAttr = nAttrCount; nAttr; --nAttr)
+ {
+ if(rAttribs.GetAttrib( nAttr - 1 )->Which() == nWhich)
+ rAttribs.RemoveAttrib( nAttr -1 );
+ }
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() );
+ mbFormatted = FALSE;
+ if(bIdleFormatAndUpdate)
+ IdleFormatAndUpdate( NULL, 0xFFFF );
+ else
+ FormatAndUpdate( NULL );
+ }
+ }
+}
+void TextEngine::RemoveAttrib( ULONG nPara, const TextCharAttrib& rAttrib )
+{
+ if ( nPara < mpDoc->GetNodes().Count() )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ if ( pNode->GetCharAttribs().Count() )
+ {
+ TextCharAttribList& rAttribs = pNode->GetCharAttribs();
+ USHORT nAttrCount = rAttribs.Count();
+ for(USHORT nAttr = nAttrCount; nAttr; --nAttr)
+ {
+ if(rAttribs.GetAttrib( nAttr - 1 ) == &rAttrib)
+ {
+ rAttribs.RemoveAttrib( nAttr -1 );
+ break;
+ }
+ }
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+ pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() );
+ mbFormatted = FALSE;
+ FormatAndUpdate( NULL );
+ }
+ }
+}
+
+void TextEngine::SetAttrib( const TextAttrib& rAttr, ULONG nPara, USHORT nStart, USHORT nEnd, BOOL bIdleFormatAndUpdate )
+{
+ // Es wird hier erstmal nicht geprueft, ob sich Attribute ueberlappen!
+ // Diese Methode ist erstmal nur fuer einen Editor, der fuer eine Zeile
+ // _schnell_ das Syntax-Highlight einstellen will.
+
+ // Da die TextEngine z.Zt fuer Editoren gedacht ist gibt es auch kein
+ // Undo fuer Attribute!
+
+ if ( nPara < mpDoc->GetNodes().Count() )
+ {
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
+
+ USHORT nMax = pNode->GetText().Len();
+ if ( nStart > nMax )
+ nStart = nMax;
+ if ( nEnd > nMax )
+ nEnd = nMax;
+
+ pNode->GetCharAttribs().InsertAttrib( new TextCharAttrib( rAttr, nStart, nEnd ) );
+ pTEParaPortion->MarkSelectionInvalid( nStart, nEnd );
+
+ mbFormatted = FALSE;
+ if ( bIdleFormatAndUpdate )
+ IdleFormatAndUpdate( NULL, 0xFFFF );
+ else
+ FormatAndUpdate( NULL );
+ }
+}
+
+void TextEngine::SetTextAlign( TxtAlign eAlign )
+{
+ if ( eAlign != meAlign )
+ {
+ meAlign = eAlign;
+ FormatFullDoc();
+ UpdateViews();
+ }
+}
+
+
+void TextEngine::ValidateSelection( TextSelection& rSel ) const
+{
+ ValidatePaM( rSel.GetStart() );
+ ValidatePaM( rSel.GetEnd() );
+}
+
+void TextEngine::ValidatePaM( TextPaM& rPaM ) const
+{
+ ULONG nMaxPara = mpDoc->GetNodes().Count() - 1;
+ if ( rPaM.GetPara() > nMaxPara )
+ {
+ rPaM.GetPara() = nMaxPara;
+ rPaM.GetIndex() = 0xFFFF;
+ }
+
+ USHORT nMaxIndex = GetTextLen( rPaM.GetPara() );
+ if ( rPaM.GetIndex() > nMaxIndex )
+ rPaM.GetIndex() = nMaxIndex;
+}
+
+
+// Status & Selektionsanpassung
+
+void TextEngine::ImpParagraphInserted( ULONG nPara )
+{
+ // Die aktive View braucht nicht angepasst werden, aber bei allen
+ // passiven muss die Selektion angepasst werden:
+ if ( mpViews->Count() > 1 )
+ {
+ for ( USHORT nView = mpViews->Count(); nView; )
+ {
+ TextView* pView = mpViews->GetObject( --nView );
+ if ( pView != GetActiveView() )
+ {
+// BOOL bInvers = pView->maSelection.GetEnd() < pView->maSelection.GetStart();
+// TextPaM& rMin = !bInvers ? pView->maSelection.GetStart(): pView->maSelection.GetEnd();
+// TextPaM& rMax = bInvers ? pView->maSelection.GetStart() : pView->maSelection.GetEnd();
+//
+// if ( rMin.GetPara() >= nPara )
+// rMin.GetPara()++;
+// if ( rMax.GetPara() >= nPara )
+// rMax.GetPara()++;
+ for ( int n = 0; n <= 1; n++ )
+ {
+ TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
+ if ( rPaM.GetPara() >= nPara )
+ rPaM.GetPara()++;
+ }
+ }
+ }
+ }
+ Broadcast( TextHint( TEXT_HINT_PARAINSERTED, nPara ) );
+}
+
+void TextEngine::ImpParagraphRemoved( ULONG nPara )
+{
+ if ( mpViews->Count() > 1 )
+ {
+ for ( USHORT nView = mpViews->Count(); nView; )
+ {
+ TextView* pView = mpViews->GetObject( --nView );
+ if ( pView != GetActiveView() )
+ {
+ ULONG nParas = mpDoc->GetNodes().Count();
+ for ( int n = 0; n <= 1; n++ )
+ {
+ TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
+ if ( rPaM.GetPara() > nPara )
+ rPaM.GetPara()--;
+ else if ( rPaM.GetPara() == nPara )
+ {
+ rPaM.GetIndex() = 0;
+ if ( rPaM.GetPara() >= nParas )
+ rPaM.GetPara()--;
+ }
+ }
+ }
+ }
+ }
+ Broadcast( TextHint( TEXT_HINT_PARAREMOVED, nPara ) );
+}
+
+void TextEngine::ImpCharsRemoved( ULONG nPara, USHORT nPos, USHORT nChars )
+{
+ if ( mpViews->Count() > 1 )
+ {
+ for ( USHORT nView = mpViews->Count(); nView; )
+ {
+ TextView* pView = mpViews->GetObject( --nView );
+ if ( pView != GetActiveView() )
+ {
+ USHORT nEnd = nPos+nChars;
+ for ( int n = 0; n <= 1; n++ )
+ {
+ TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
+ if ( rPaM.GetPara() == nPara )
+ {
+ if ( rPaM.GetIndex() > nEnd )
+ rPaM.GetIndex() = rPaM.GetIndex() - nChars;
+ else if ( rPaM.GetIndex() > nPos )
+ rPaM.GetIndex() = nPos;
+ }
+ }
+ }
+ }
+ }
+ Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) );
+}
+
+void TextEngine::ImpCharsInserted( ULONG nPara, USHORT nPos, USHORT nChars )
+{
+ if ( mpViews->Count() > 1 )
+ {
+ for ( USHORT nView = mpViews->Count(); nView; )
+ {
+ TextView* pView = mpViews->GetObject( --nView );
+ if ( pView != GetActiveView() )
+ {
+ for ( int n = 0; n <= 1; n++ )
+ {
+ TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
+ if ( rPaM.GetPara() == nPara )
+ {
+ if ( rPaM.GetIndex() >= nPos )
+ rPaM.GetIndex() = rPaM.GetIndex() + nChars;
+ }
+ }
+ }
+ }
+ }
+ Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) );
+}
+
+void TextEngine::ImpFormattingParagraph( ULONG nPara )
+{
+ Broadcast( TextHint( TEXT_HINT_FORMATPARA, nPara ) );
+}
+
+void TextEngine::ImpTextHeightChanged()
+{
+ Broadcast( TextHint( TEXT_HINT_TEXTHEIGHTCHANGED ) );
+}
+
+void TextEngine::ImpTextFormatted()
+{
+ Broadcast( TextHint( TEXT_HINT_TEXTFORMATTED ) );
+}
+
+void TextEngine::Draw( OutputDevice* pDev, const Point& rPos )
+{
+ ImpPaint( pDev, rPos, NULL );
+}
+
+void TextEngine::SetLeftMargin( USHORT n )
+{
+ mpDoc->SetLeftMargin( n );
+}
+
+USHORT TextEngine::GetLeftMargin() const
+{
+ return mpDoc->GetLeftMargin();
+}
+
+uno::Reference< i18n::XBreakIterator > TextEngine::GetBreakIterator()
+{
+ if ( !mxBreakIterator.is() )
+ mxBreakIterator = vcl::unohelper::CreateBreakIterator();
+ DBG_ASSERT( mxBreakIterator.is(), "Could not create BreakIterator" );
+ return mxBreakIterator;
+}
+
+void TextEngine::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
+{
+ maLocale = rLocale;
+ delete mpLocaleDataWrapper;
+ mpLocaleDataWrapper = NULL;
+}
+
+::com::sun::star::lang::Locale TextEngine::GetLocale()
+{
+ if ( !maLocale.Language.getLength() )
+ {
+ maLocale = Application::GetSettings().GetUILocale();
+ }
+ return maLocale;
+}
+
+LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper()
+{
+ if ( !mpLocaleDataWrapper )
+ mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() );
+
+ return mpLocaleDataWrapper;
+}
+
+void TextEngine::SetRightToLeft( BOOL bR2L )
+{
+ if ( mbRightToLeft != bR2L )
+ {
+ mbRightToLeft = bR2L;
+ meAlign = bR2L ? TXTALIGN_RIGHT : TXTALIGN_LEFT;
+ FormatFullDoc();
+ UpdateViews();
+ }
+}
+
+void TextEngine::ImpInitWritingDirections( ULONG nPara )
+{
+ TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
+ TEWritingDirectionInfos& rInfos = pParaPortion->GetWritingDirectionInfos();
+ rInfos.Remove( 0, rInfos.Count() );
+
+ if ( pParaPortion->GetNode()->GetText().Len() )
+ {
+ const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/;
+ String aText( pParaPortion->GetNode()->GetText() );
+
+ //
+ // Bidi functions from icu 2.0
+ //
+ UErrorCode nError = U_ZERO_ERROR;
+ UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError );
+ nError = U_ZERO_ERROR;
+
+ ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW
+ nError = U_ZERO_ERROR;
+
+ long nCount = ubidi_countRuns( pBidi, &nError );
+
+ int32_t nStart = 0;
+ int32_t nEnd;
+ UBiDiLevel nCurrDir;
+
+ for ( USHORT nIdx = 0; nIdx < nCount; ++nIdx )
+ {
+ ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir );
+ rInfos.Insert( TEWritingDirectionInfo( nCurrDir, (USHORT)nStart, (USHORT)nEnd ), rInfos.Count() );
+ nStart = nEnd;
+ }
+
+ ubidi_close( pBidi );
+ }
+
+ // No infos mean no CTL and default dir is L2R...
+ if ( !rInfos.Count() )
+ rInfos.Insert( TEWritingDirectionInfo( 0, 0, (USHORT)pParaPortion->GetNode()->GetText().Len() ), rInfos.Count() );
+
+}
+
+BYTE TextEngine::ImpGetRightToLeft( ULONG nPara, USHORT nPos, USHORT* pStart, USHORT* pEnd )
+{
+ BYTE nRightToLeft = 0;
+
+ TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
+ if ( pNode && pNode->GetText().Len() )
+ {
+ TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
+ if ( !pParaPortion->GetWritingDirectionInfos().Count() )
+ ImpInitWritingDirections( nPara );
+
+ TEWritingDirectionInfos& rDirInfos = pParaPortion->GetWritingDirectionInfos();
+ for ( USHORT n = 0; n < rDirInfos.Count(); n++ )
+ {
+ if ( ( rDirInfos[n].nStartPos <= nPos ) && ( rDirInfos[n].nEndPos >= nPos ) )
+ {
+ nRightToLeft = rDirInfos[n].nType;
+ if ( pStart )
+ *pStart = rDirInfos[n].nStartPos;
+ if ( pEnd )
+ *pEnd = rDirInfos[n].nEndPos;
+ break;
+ }
+ }
+ }
+ return nRightToLeft;
+}
+
+long TextEngine::ImpGetPortionXOffset( ULONG nPara, TextLine* pLine, USHORT nTextPortion )
+{
+ long nX = pLine->GetStartX();
+
+ TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
+
+ for ( USHORT i = pLine->GetStartPortion(); i < nTextPortion; i++ )
+ {
+ TETextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( i );
+ nX += pPortion->GetWidth();
+ }
+
+ TETextPortion* pDestPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion );
+ if ( pDestPortion->GetKind() != PORTIONKIND_TAB )
+ {
+ if ( !IsRightToLeft() && pDestPortion->GetRightToLeft() )
+ {
+ // Portions behind must be added, visual before this portion
+ sal_uInt16 nTmpPortion = nTextPortion+1;
+ while ( nTmpPortion <= pLine->GetEndPortion() )
+ {
+ TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion );
+ if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) )
+ nX += pNextTextPortion->GetWidth();
+ else
+ break;
+ nTmpPortion++;
+ }
+ // Portions before must be removed, visual behind this portion
+ nTmpPortion = nTextPortion;
+ while ( nTmpPortion > pLine->GetStartPortion() )
+ {
+ --nTmpPortion;
+ TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion );
+ if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) )
+ nX -= pPrevTextPortion->GetWidth();
+ else
+ break;
+ }
+ }
+ else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() )
+ {
+ // Portions behind must be removed, visual behind this portion
+ sal_uInt16 nTmpPortion = nTextPortion+1;
+ while ( nTmpPortion <= pLine->GetEndPortion() )
+ {
+ TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion );
+ if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) )
+ nX += pNextTextPortion->GetWidth();
+ else
+ break;
+ nTmpPortion++;
+ }
+ // Portions before must be added, visual before this portion
+ nTmpPortion = nTextPortion;
+ while ( nTmpPortion > pLine->GetStartPortion() )
+ {
+ --nTmpPortion;
+ TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion );
+ if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) )
+ nX -= pPrevTextPortion->GetWidth();
+ else
+ break;
+ }
+ }
+ }
+/*
+ if ( IsRightToLeft() )
+ {
+ // Switch X postions...
+ DBG_ASSERT( GetMaxTextWidth(), "GetPortionXOffset - max text width?!" );
+ DBG_ASSERT( nX <= (long)GetMaxTextWidth(), "GetPortionXOffset - position out of paper size!" );
+ nX = GetMaxTextWidth() - nX;
+ nX -= pDestPortion->GetWidth();
+ }
+*/
+
+ return nX;
+}
+
+void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev, BOOL bDrawingR2LPortion )
+{
+ ULONG nLayoutMode = pOutDev->GetLayoutMode();
+
+ nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG );
+ if ( bDrawingR2LPortion )
+ nLayoutMode |= TEXT_LAYOUT_BIDI_RTL;
+
+ pOutDev->SetLayoutMode( nLayoutMode );
+}
+
+TxtAlign TextEngine::ImpGetAlign() const
+{
+ TxtAlign eAlign = meAlign;
+ if ( IsRightToLeft() )
+ {
+ if ( eAlign == TXTALIGN_LEFT )
+ eAlign = TXTALIGN_RIGHT;
+ else if ( eAlign == TXTALIGN_RIGHT )
+ eAlign = TXTALIGN_LEFT;
+ }
+ return eAlign;
+}
+
+long TextEngine::ImpGetOutputOffset( ULONG nPara, TextLine* pLine, USHORT nIndex, USHORT nIndex2 )
+{
+ TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
+
+ USHORT nPortionStart;
+ USHORT nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, TRUE );
+
+ TETextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( nPortion );
+
+ long nX;
+
+ if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 ) )
+ {
+ // Output of full portion, so we need portion x offset.
+ // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portioon, depending on R2L, L2R
+ nX = ImpGetPortionXOffset( nPara, pLine, nPortion );
+ if ( IsRightToLeft() )
+ {
+ nX = -nX -pTextPortion->GetWidth();
+ }
+ }
+ else
+ {
+ nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart );
+ if ( nIndex2 != nIndex )
+ {
+ long nX2 = ImpGetXPos( nPara, pLine, nIndex2, FALSE );
+ if ( ( !IsRightToLeft() && ( nX2 < nX ) ) ||
+ ( IsRightToLeft() && ( nX2 > nX ) ) )
+ {
+ nX = nX2;
+ }
+ }
+ if ( IsRightToLeft() )
+ {
+ nX = -nX;
+ }
+ }
+
+ return nX;
+}
diff --git a/svtools/source/edit/textund2.hxx b/svtools/source/edit/textund2.hxx
new file mode 100644
index 000000000000..18cf9331328e
--- /dev/null
+++ b/svtools/source/edit/textund2.hxx
@@ -0,0 +1,148 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _TEXTUND2_HXX
+#define _TEXTUND2_HXX
+
+#include <textundo.hxx>
+
+
+class TextUndoDelPara : public TextUndo
+{
+private:
+ BOOL mbDelObject;
+ ULONG mnPara;
+ TextNode* mpNode; // Zeigt auf das gueltige, nicht zerstoerte Objekt!
+
+public:
+ TYPEINFO();
+ TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, ULONG nPara );
+ ~TextUndoDelPara();
+
+ virtual void Undo();
+ virtual void Redo();
+};
+
+
+class TextUndoConnectParas : public TextUndo
+{
+private:
+ ULONG mnPara;
+ USHORT mnSepPos;
+
+public:
+ TYPEINFO();
+ TextUndoConnectParas( TextEngine* pTextEngine, ULONG nPara, USHORT nSepPos );
+ ~TextUndoConnectParas();
+
+ virtual void Undo();
+ virtual void Redo();
+};
+
+
+class TextUndoSplitPara : public TextUndo
+{
+private:
+ ULONG mnPara;
+ USHORT mnSepPos;
+
+public:
+ TYPEINFO();
+ TextUndoSplitPara( TextEngine* pTextEngine, ULONG nPara, USHORT nSepPos );
+ ~TextUndoSplitPara();
+
+ virtual void Undo();
+ virtual void Redo();
+};
+
+
+class TextUndoInsertChars : public TextUndo
+{
+private:
+ TextPaM maTextPaM;
+ String maText;
+
+public:
+ TYPEINFO();
+ TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const String& rStr );
+
+// const TextPaM& GetTextPaM() { return aTextPaM; }
+// String& GetStr() { return aText; }
+
+ virtual void Undo();
+ virtual void Redo();
+
+ virtual BOOL Merge( SfxUndoAction *pNextAction );
+};
+
+
+class TextUndoRemoveChars : public TextUndo
+{
+private:
+ TextPaM maTextPaM;
+ String maText;
+
+public:
+ TYPEINFO();
+ TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const String& rStr );
+
+// const TextPaM& GetTextPaM() { return aTextPaM; }
+// String& GetStr() { return aText; }
+
+ virtual void Undo();
+ virtual void Redo();
+};
+
+
+class TextUndoSetAttribs: public TextUndo
+{
+private:
+ TextSelection maSelection;
+// SfxItemSet aNewAttribs;
+// TextInfoArray aPrevAttribs;
+// BYTE nSpecial;
+// BOOL bSetIsRemove;
+// USHORT nRemoveWhich;
+//
+// void ImpSetSelection( TextView* pView );
+
+
+public:
+ TYPEINFO();
+ TextUndoSetAttribs( TextEngine* pTextEngine, const TextSelection& rESel );
+ ~TextUndoSetAttribs();
+
+// TextInfoArray& GetTextInfos() { return aPrevAttribs; }
+// SfxItemSet& GetNewAttribs() { return aNewAttribs; }
+// void SetSpecial( BYTE n ) { nSpecial = n; }
+// void SetRemoveAttribs( BOOL b ) { bSetIsRemove = b; }
+// void SetRemoveWhich( USHORT n ) { nRemoveWhich = n; }
+
+ virtual void Undo();
+ virtual void Redo();
+};
+
+#endif // _TEXTUND2_HXX
diff --git a/svtools/source/edit/textundo.cxx b/svtools/source/edit/textundo.cxx
new file mode 100644
index 000000000000..4c243de16c31
--- /dev/null
+++ b/svtools/source/edit/textundo.cxx
@@ -0,0 +1,343 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/texteng.hxx>
+#include <svtools/textview.hxx>
+#include <textundo.hxx>
+#include <textund2.hxx>
+#include <svtools/textdata.hxx>
+#include <textdoc.hxx>
+#include <textdat2.hxx>
+
+TYPEINIT1( TextUndo, SfxUndoAction );
+TYPEINIT1( TextUndoDelPara, TextUndo );
+TYPEINIT1( TextUndoConnectParas, TextUndo );
+TYPEINIT1( TextUndoSplitPara, TextUndo );
+TYPEINIT1( TextUndoInsertChars, TextUndo );
+TYPEINIT1( TextUndoRemoveChars, TextUndo );
+TYPEINIT1( TextUndoSetAttribs, TextUndo );
+
+
+TextUndoManager::TextUndoManager( TextEngine* p )
+{
+ mpTextEngine = p;
+}
+
+TextUndoManager::~TextUndoManager()
+{
+}
+
+BOOL __EXPORT TextUndoManager::Undo( USHORT nCount )
+{
+ if ( GetUndoActionCount() == 0 )
+ return FALSE;
+
+ UndoRedoStart();
+
+ mpTextEngine->SetIsInUndo( TRUE );
+ BOOL bDone = SfxUndoManager::Undo( nCount );
+ mpTextEngine->SetIsInUndo( FALSE );
+
+ UndoRedoEnd();
+
+ return bDone;
+}
+
+BOOL __EXPORT TextUndoManager::Redo( USHORT nCount )
+{
+ if ( GetRedoActionCount() == 0 )
+ return FALSE;
+
+
+ UndoRedoStart();
+
+ mpTextEngine->SetIsInUndo( TRUE );
+ BOOL bDone = SfxUndoManager::Redo( nCount );
+ mpTextEngine->SetIsInUndo( FALSE );
+
+ UndoRedoEnd();
+
+ return bDone;
+}
+
+void TextUndoManager::UndoRedoStart()
+{
+ DBG_ASSERT( GetView(), "Undo/Redo: Active View?" );
+
+// if ( GetView() )
+// GetView()->HideSelection();
+}
+
+void TextUndoManager::UndoRedoEnd()
+{
+ if ( GetView() )
+ {
+ TextSelection aNewSel( GetView()->GetSelection() );
+ aNewSel.GetStart() = aNewSel.GetEnd();
+ GetView()->ImpSetSelection( aNewSel );
+ }
+
+ mpTextEngine->UpdateSelections();
+
+ mpTextEngine->FormatAndUpdate( GetView() );
+}
+
+
+TextUndo::TextUndo( USHORT nI, TextEngine* p )
+{
+ mnId = nI;
+ mpTextEngine = p;
+}
+
+TextUndo::~TextUndo()
+{
+}
+
+USHORT __EXPORT TextUndo::GetId() const
+{
+ //nId sollte mal entfallen => GetId ueberall ueberladen...
+ return mnId;
+}
+
+XubString __EXPORT TextUndo::GetComment() const
+{
+// return mpTextEngine->GetUndoComment( this );
+ return String();
+}
+
+void TextUndo::SetSelection( const TextSelection& rSel )
+{
+ if ( GetView() )
+ GetView()->ImpSetSelection( rSel );
+}
+
+
+TextUndoDelPara::TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, ULONG nPara )
+ : TextUndo( TEXTUNDO_DELCONTENT, pTextEngine )
+{
+ mpNode = pNode;
+ mnPara = nPara;
+ mbDelObject = TRUE;
+}
+
+TextUndoDelPara::~TextUndoDelPara()
+{
+ if ( mbDelObject )
+ delete mpNode;
+}
+
+void __EXPORT TextUndoDelPara::Undo()
+{
+ GetTextEngine()->InsertContent( mpNode, mnPara );
+ mbDelObject = FALSE; // gehoert wieder der Engine
+
+ if ( GetView() )
+ {
+ TextSelection aSel( TextPaM( mnPara, 0 ), TextPaM( mnPara, mpNode->GetText().Len() ) );
+ SetSelection( aSel );
+ }
+}
+
+void __EXPORT TextUndoDelPara::Redo()
+{
+ // pNode stimmt nicht mehr, falls zwischendurch Undos, in denen
+ // Absaetze verschmolzen sind.
+ mpNode = GetDoc()->GetNodes().GetObject( mnPara );
+
+ delete GetTEParaPortions()->GetObject( mnPara );
+ GetTEParaPortions()->Remove( mnPara );
+
+ // Node nicht loeschen, haengt im Undo!
+ GetDoc()->GetNodes().Remove( mnPara );
+ GetTextEngine()->ImpParagraphRemoved( mnPara );
+
+ mbDelObject = TRUE; // gehoert wieder dem Undo
+
+ ULONG nParas = GetDoc()->GetNodes().Count();
+ ULONG n = mnPara < nParas ? mnPara : (nParas-1);
+ TextNode* pN = GetDoc()->GetNodes().GetObject( n );
+ TextPaM aPaM( n, pN->GetText().Len() );
+ SetSelection( aPaM );
+}
+
+ // -----------------------------------------------------------------------
+// TextUndoConnectParas
+// ------------------------------------------------------------------------
+TextUndoConnectParas::TextUndoConnectParas( TextEngine* pTextEngine, ULONG nPara, USHORT nPos )
+ : TextUndo( TEXTUNDO_CONNECTPARAS, pTextEngine )
+{
+ mnPara = nPara;
+ mnSepPos = nPos;
+}
+
+TextUndoConnectParas::~TextUndoConnectParas()
+{
+}
+
+void __EXPORT TextUndoConnectParas::Undo()
+{
+ TextPaM aPaM = GetTextEngine()->SplitContent( mnPara, mnSepPos );
+ SetSelection( aPaM );
+}
+
+void __EXPORT TextUndoConnectParas::Redo()
+{
+ TextPaM aPaM = GetTextEngine()->ConnectContents( mnPara );
+ SetSelection( aPaM );
+}
+
+
+TextUndoSplitPara::TextUndoSplitPara( TextEngine* pTextEngine, ULONG nPara, USHORT nPos )
+ : TextUndo( TEXTUNDO_SPLITPARA, pTextEngine )
+{
+ mnPara = nPara;
+ mnSepPos = nPos;
+}
+
+TextUndoSplitPara::~TextUndoSplitPara()
+{
+}
+
+void __EXPORT TextUndoSplitPara::Undo()
+{
+ TextPaM aPaM = GetTextEngine()->ConnectContents( mnPara );
+ SetSelection( aPaM );
+}
+
+void __EXPORT TextUndoSplitPara::Redo()
+{
+ TextPaM aPaM = GetTextEngine()->SplitContent( mnPara, mnSepPos );
+ SetSelection( aPaM );
+}
+
+
+TextUndoInsertChars::TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr )
+ : TextUndo( TEXTUNDO_INSERTCHARS, pTextEngine ),
+ maTextPaM( rTextPaM ), maText( rStr )
+{
+}
+
+void __EXPORT TextUndoInsertChars::Undo()
+{
+ TextSelection aSel( maTextPaM, maTextPaM );
+ aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len();
+ TextPaM aPaM = GetTextEngine()->ImpDeleteText( aSel );
+ SetSelection( aPaM );
+}
+
+void __EXPORT TextUndoInsertChars::Redo()
+{
+ TextSelection aSel( maTextPaM, maTextPaM );
+ GetTextEngine()->ImpInsertText( aSel, maText );
+ TextPaM aNewPaM( maTextPaM );
+ aNewPaM.GetIndex() = aNewPaM.GetIndex() + maText.Len();
+ SetSelection( TextSelection( aSel.GetStart(), aNewPaM ) );
+}
+
+BOOL __EXPORT TextUndoInsertChars::Merge( SfxUndoAction* pNextAction )
+{
+ if ( !pNextAction->ISA( TextUndoInsertChars ) )
+ return FALSE;
+
+ TextUndoInsertChars* pNext = (TextUndoInsertChars*)pNextAction;
+
+ if ( maTextPaM.GetPara() != pNext->maTextPaM.GetPara() )
+ return FALSE;
+
+ if ( ( maTextPaM.GetIndex() + maText.Len() ) == pNext->maTextPaM.GetIndex() )
+ {
+ maText += pNext->maText;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+TextUndoRemoveChars::TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr )
+ : TextUndo( TEXTUNDO_REMOVECHARS, pTextEngine ),
+ maTextPaM( rTextPaM ), maText( rStr )
+{
+}
+
+void __EXPORT TextUndoRemoveChars::Undo()
+{
+ TextSelection aSel( maTextPaM, maTextPaM );
+ GetTextEngine()->ImpInsertText( aSel, maText );
+ aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len();
+ SetSelection( aSel );
+}
+
+void __EXPORT TextUndoRemoveChars::Redo()
+{
+ TextSelection aSel( maTextPaM, maTextPaM );
+ aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len();
+ TextPaM aPaM = GetTextEngine()->ImpDeleteText( aSel );
+ SetSelection( aPaM );
+}
+
+
+TextUndoSetAttribs::TextUndoSetAttribs( TextEngine* pTextEngine, const TextSelection& rSel )
+ : TextUndo( TEXTUNDO_ATTRIBS, pTextEngine ), maSelection( rSel )
+{
+ maSelection.Justify();
+// aNewAttribs.Set( rNewItems );
+// mbSetIsRemove = FALSE;
+// mnRemoveWhich = 0;
+// mnSpecial = 0;
+}
+
+TextUndoSetAttribs::~TextUndoSetAttribs()
+{
+ // ...............
+}
+
+void __EXPORT TextUndoSetAttribs::Undo()
+{
+ for ( ULONG nPara = maSelection.GetStart().GetPara(); nPara <= maSelection.GetEnd().GetPara(); nPara++ )
+ {
+// ContentAttribsInfo* pInf = aPrevAttribs[ (USHORT)(nPara-aESel.nStartPara) ];
+// GetTextEngine()->RemoveCharAttribs( nPara );
+// TextNode* pNode = GetTextEngine()->GetTextDoc().GetObject( nPara );
+// for ( USHORT nAttr = 0; nAttr < pInf->GetPrevCharAttribs().Count(); nAttr++ )
+// {
+// GetTextEngine()->GetTextDoc().InsertAttrib( pNode, pX->GetStart(), pX->GetEnd(), *pX->GetItem() );
+// }
+ }
+ SetSelection( maSelection );
+}
+
+void __EXPORT TextUndoSetAttribs::Redo()
+{
+// if ( !bSetIsRemove )
+// GetTextEngine()->SetAttribs( aSel, aNewAttribs, nSpecial );
+// else
+// GetTextEngine()->RemoveCharAttribs( aSel, bRemoveParaAttribs, nRemoveWhich );
+ SetSelection( maSelection );
+}
diff --git a/svtools/source/edit/textundo.hxx b/svtools/source/edit/textundo.hxx
new file mode 100644
index 000000000000..cc26c0b51ef6
--- /dev/null
+++ b/svtools/source/edit/textundo.hxx
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _TEXTUNDO_HXX
+#define _TEXTUNDO_HXX
+
+#include <svl/undo.hxx>
+
+class TextEngine;
+
+class TextUndoManager : public SfxUndoManager
+{
+ TextEngine* mpTextEngine;
+
+protected:
+
+ void UndoRedoStart();
+ void UndoRedoEnd();
+
+ TextView* GetView() const { return mpTextEngine->GetActiveView(); }
+
+public:
+ TextUndoManager( TextEngine* pTextEngine );
+ ~TextUndoManager();
+
+ using SfxUndoManager::Undo;
+ virtual BOOL Undo( USHORT nCount=1 );
+ using SfxUndoManager::Redo;
+ virtual BOOL Redo( USHORT nCount=1 );
+
+};
+
+class TextUndo : public SfxUndoAction
+{
+private:
+ USHORT mnId;
+ TextEngine* mpTextEngine;
+
+protected:
+
+ TextView* GetView() const { return mpTextEngine->GetActiveView(); }
+ void SetSelection( const TextSelection& rSel );
+
+ TextDoc* GetDoc() const { return mpTextEngine->mpDoc; }
+ TEParaPortions* GetTEParaPortions() const { return mpTextEngine->mpTEParaPortions; }
+
+public:
+ TYPEINFO();
+ TextUndo( USHORT nId, TextEngine* pTextEngine );
+ virtual ~TextUndo();
+
+ TextEngine* GetTextEngine() const { return mpTextEngine; }
+
+ virtual void Undo() = 0;
+ virtual void Redo() = 0;
+
+ virtual XubString GetComment() const;
+ virtual USHORT GetId() const;
+};
+
+#endif // _TEXTUNDO_HXX
diff --git a/svtools/source/edit/textview.cxx b/svtools/source/edit/textview.cxx
new file mode 100644
index 000000000000..48cd23bdcc6f
--- /dev/null
+++ b/svtools/source/edit/textview.cxx
@@ -0,0 +1,2470 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+#include <svtools/textview.hxx>
+#include <svtools/texteng.hxx>
+#include <textdoc.hxx>
+#include <svtools/textdata.hxx>
+#include <textdat2.hxx>
+
+#include <svl/undo.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/sound.hxx>
+#include <tools/stream.hxx>
+
+#include <sot/formats.hxx>
+#include <svl/urlbmk.hxx>
+
+#ifndef _COM_SUN_STAR_TEXT_XBREAKITERATOR_HPP_
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_CHARACTERITERATORMODE_HPP_
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
+#include <com/sun/star/i18n/WordType.hpp>
+#endif
+#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>
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#endif
+#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 <sot/formats.hxx>
+
+#include <vos/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, SAL_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;
+
+ 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 );
+ 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 );
+ 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)
+{
+ ULONG nT = SotExchange::GetFormat( rFlavor );
+ return ( nT == SOT_FORMAT_STRING );
+}
+
+/*-- 24.06.2004 13:54:36---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+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;
+
+ USHORT mnTravelXPos;
+
+ BOOL mbAutoScroll : 1;
+ BOOL mbInsertMode : 1;
+ BOOL mbReadOnly : 1;
+ BOOL mbPaintSelection : 1;
+ BOOL mbAutoIndent : 1;
+ BOOL mbHighlightSelection : 1;
+ BOOL mbCursorEnabled : 1;
+ BOOL mbClickedInSelection : 1;
+ BOOL mbSupportProtectAttribute : 1;
+ bool mbCursorAtEndOfLine;
+};
+
+// -------------------------------------------------------------------------
+// (+) class TextView
+// -------------------------------------------------------------------------
+TextView::TextView( TextEngine* pEng, Window* pWindow ) :
+ mpImpl(new ImpTextView)
+{
+ pWindow->EnableRTL( FALSE );
+
+ mpImpl->mpWindow = pWindow;
+ mpImpl->mpTextEngine = pEng;
+ mpImpl->mpVirtDev = NULL;
+
+ mpImpl->mbPaintSelection = TRUE;
+ mpImpl->mbAutoScroll = TRUE;
+ mpImpl->mbInsertMode = TRUE;
+ mpImpl->mbReadOnly = FALSE;
+ mpImpl->mbHighlightSelection = FALSE;
+ mpImpl->mbAutoIndent = FALSE;
+ mpImpl->mbCursorEnabled = TRUE;
+ mpImpl->mbClickedInSelection = FALSE;
+ mpImpl->mbSupportProtectAttribute = FALSE;
+ mpImpl->mbCursorAtEndOfLine = false;
+// mbInSelection = 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( 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 = 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, 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( TEXTUNDO_DELETE );
+ TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection );
+ mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE );
+
+ 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, FALSE );
+}
+
+void TextView::ImpPaint( const Rectangle& rRect, 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 );
+
+ 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 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;
+ ULONG nStartPara = aSel.GetStart().GetPara();
+ ULONG nEndPara = aSel.GetEnd().GetPara();
+ for ( 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 );
+ 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( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), FALSE ) );
+ aTmpRec.Top() += nY;
+ aTmpRec.Bottom() += nY;
+ Point aTopLeft( aTmpRec.TopLeft() );
+
+ aTmpRec = mpImpl->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 );
+ 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( TRUE );
+}
+
+void TextView::HideSelection()
+{
+ ImpShowHideSelection( FALSE );
+}
+
+void TextView::ShowSelection( const TextSelection& rRange )
+{
+ ImpShowHideSelection( TRUE, &rRange );
+}
+
+void TextView::ImpShowHideSelection( 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();
+ 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;
+}
+
+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 = mpImpl->mpTextEngine->IsModified();
+ mpImpl->mpTextEngine->SetModified( FALSE );
+
+ TextSelection aCurSel( mpImpl->maSelection );
+ TextSelection aOldSel( aCurSel );
+
+ USHORT 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 = TRUE;
+ if ( nCode == KEY_END )
+ bEndKey = TRUE;
+ }
+ else
+ bDone = 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() )
+ {
+ 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;
+
+ 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( TEXTUNDO_DELETE );
+ 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( TEXTUNDO_DELETE );
+ bModified = TRUE;
+ bAllowIdle = FALSE;
+ }
+ else
+ bDone = FALSE;
+ }
+ break;
+ case KEY_TAB:
+ {
+ if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() &&
+ !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() &&
+ ImplCheckTextLen( 'x' ) )
+ {
+ aCurSel = mpImpl->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 ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() &&
+ !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( 'x' ) )
+ {
+ mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
+ aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel );
+ if ( mpImpl->mbAutoIndent )
+ {
+ TextNode* pPrev = mpImpl->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 = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) );
+ }
+ mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
+ bModified = TRUE;
+ }
+ else
+ bDone = 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( nCharCode ) ) // sonst trotzdem das Zeichen schlucken...
+ {
+ aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True );
+ bModified = TRUE;
+ }
+ }
+ else
+ bDone = 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( INPUT_KEYBOARD) )
+ mpImpl->mpTextEngine->IdleFormatAndUpdate( this );
+ else
+ mpImpl->mpTextEngine->FormatAndUpdate( this);
+ }
+ else if ( bMoved )
+ {
+ // Selection wird jetzt gezielt in ImpMoveCursor gemalt.
+ ImpShowCursor( mpImpl->mbAutoScroll, TRUE, bEndKey );
+ }
+
+ if ( mpImpl->mpTextEngine->IsModified() )
+ mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) );
+ else if ( bWasModified )
+ mpImpl->mpTextEngine->SetModified( TRUE );
+
+ return bDone;
+}
+
+void TextView::MouseButtonUp( const MouseEvent& rMouseEvent )
+{
+ mpImpl->mbClickedInSelection = 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() = (USHORT)aBoundary.startPos;
+ aNewSel.GetEnd().GetIndex() = (USHORT)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(),
+ (USHORT)aBoundary.startPos),
+ TEXTATTR_PROTECTED );
+ const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib(
+ TextPaM(aNewSel.GetEnd().GetPara(),
+ (USHORT)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( TRUE, 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( TRUE, 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 );
+
+ 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 )
+ {
+ USHORT nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen;
+ USHORT nNewIMETextLen = pData->GetText().Len();
+
+ if ( ( nOldIMETextLen > nNewIMETextLen ) &&
+ ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) )
+ {
+ // restore old characters
+ USHORT 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
+ USHORT 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 );
+
+ USHORT 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() );
+ USHORT nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True );
+ TextLine* pLine = pParaPortion->GetLines().GetObject( 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( BOOL bGotoCursor, BOOL bForceVisCursor )
+{
+ // Die Einstellung hat mehr Gewicht:
+ if ( !mpImpl->mbAutoScroll )
+ bGotoCursor = FALSE;
+ ImpShowCursor( bGotoCursor, bForceVisCursor, 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 )
+ {
+ 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( 1 );
+}
+
+void TextView::Redo()
+{
+ mpImpl->mpTextEngine->SetActiveView( this );
+ mpImpl->mpTextEngine->GetUndoManager().Redo( 0 );
+}
+
+void TextView::Cut()
+{
+ mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_CUT );
+ Copy();
+ DeleteSelected();
+ mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_CUT );
+}
+
+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, 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, 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( BOOL bInsert )
+{
+ if ( mpImpl->mbInsertMode != bInsert )
+ {
+ mpImpl->mbInsertMode = bInsert;
+ ShowCursor( mpImpl->mbAutoScroll, FALSE );
+ }
+}
+
+void TextView::SetReadOnly( BOOL bReadOnly )
+{
+ if ( mpImpl->mbReadOnly != bReadOnly )
+ {
+ mpImpl->mbReadOnly = bReadOnly;
+ if ( !mpImpl->mbReadOnly )
+ ShowCursor( mpImpl->mbAutoScroll, 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 );
+
+ BOOL bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? TRUE : FALSE;
+ USHORT 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() ? (USHORT)i18n::CharacterIteratorMode::SKIPCHARACTER : (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
+ break;
+ case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (USHORT)i18n::CharacterIteratorMode::SKIPCHARACTER : (USHORT)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 aOldSelection( mpImpl->maSelection );
+ 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, BOOL bSelect )
+{
+ InsertNewText( rStr, bSelect );
+}
+
+void TextView::InsertNewText( const rtl::OUString& rStr, BOOL bSelect )
+{
+// HideSelection();
+ mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
+
+ /* #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;
+ while( nLen )
+ {
+ 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;
+ }
+ mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
+
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+}
+
+/*
+void TextView::InsertText( const XubString& rStr, BOOL bSelect )
+{
+// HideSelection();
+
+ TextSelection aNewSel( mpImpl->maSelection );
+
+ mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT );
+ TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, rStr );
+ mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT );
+
+ if ( bSelect )
+ {
+ aNewSel.Justify();
+ aNewSel.GetEnd() = aPaM;
+ }
+ else
+ {
+ aNewSel = aPaM;
+ }
+
+ ImpSetSelection( aNewSel );
+
+ mpImpl->mpTextEngine->FormatAndUpdate( this );
+}
+*/
+
+// OLD
+TextPaM TextView::CursorLeft( const TextPaM& rPaM, BOOL bWordMode )
+{
+ return bWordMode ? CursorWordLeft( rPaM ) : CursorLeft( rPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
+
+ // Remove (USHORT) typecasts in this file when removing this method!
+}
+
+// OLD
+TextPaM TextView::CursorRight( const TextPaM& rPaM, BOOL bWordMode )
+{
+ return bWordMode ? CursorWordRight( rPaM ) : CursorRight( rPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
+
+ // Remove (USHORT) typecasts in this file when removing this method!
+}
+
+TextPaM TextView::CursorLeft( const TextPaM& rPaM, USHORT 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() = (USHORT)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, USHORT 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() = (USHORT)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 ) ? (USHORT)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() = (USHORT)aBoundary.startPos;
+ }
+ else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) )
+ {
+ aPaM.GetPara()++;
+ aPaM.GetIndex() = 0;
+ }
+
+ return aPaM;
+}
+
+TextPaM TextView::ImpDelete( BYTE nMode, BYTE 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, (USHORT)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) ? (USHORT)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, (USHORT)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() = (USHORT)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, FALSE ).Left();
+ mpImpl->mnTravelXPos = (USHORT)nX+1;
+ }
+ else
+ nX = mpImpl->mnTravelXPos;
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), FALSE );
+ if ( nLine ) // gleicher Absatz
+ {
+ USHORT 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().GetObject( 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() );
+ USHORT nL = pPPortion->GetLines().Count() - 1;
+ USHORT 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, FALSE ).Left();
+ mpImpl->mnTravelXPos = (USHORT)nX+1;
+ }
+ else
+ nX = mpImpl->mnTravelXPos;
+
+ TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() );
+ USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), FALSE );
+ if ( nLine < ( pPPortion->GetLines().Count() - 1 ) )
+ {
+ USHORT nCharPos = mpImpl->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() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz
+ {
+ aPaM.GetPara()++;
+ pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+ USHORT nCharPos = mpImpl->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 = mpImpl->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 = mpImpl->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 = 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()
+{
+ 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( BOOL bGotoCursor, BOOL bForceVisCursor, BOOL bSpecial )
+{
+ if ( mpImpl->mpTextEngine->IsFormatting() )
+ return;
+ if ( mpImpl->mpTextEngine->GetUpdateMode() == 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(), TRUE ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), 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, FALSE, TRUE ).Left();
+
+ TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() );
+
+ USHORT nTextPortionStart = 0;
+ USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, TRUE );
+ TETextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion );
+ if ( pTextPortion->GetKind() == PORTIONKIND_TAB )
+ {
+ if ( mpImpl->mpTextEngine->IsRightToLeft() )
+ {
+
+ }
+ aEditCursor.Right() += pTextPortion->GetWidth();
+ }
+ else
+ {
+ TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (USHORT)i18n::CharacterIteratorMode::SKIPCELL );
+ aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, 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:
+// 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();
+}
+
+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 );
+ }
+
+ BOOL bForceCursor = mpImpl->mpDDInfo ? FALSE : TRUE; // && !mbInSelection
+ ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, FALSE );
+ return TRUE;
+}
+
+BOOL TextView::IsSelectionAtPoint( const Point& rPosPixel )
+{
+// if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection )
+// return FALSE;
+
+ Point aDocPos = GetDocPos( rPosPixel );
+ TextPaM aPaM = mpImpl->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 ) ||
+ ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) );
+}
+
+BOOL TextView::IsInSelection( const TextPaM& rPaM )
+{
+ TextSelection aSel = mpImpl->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 ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor )
+ {
+ mpImpl->mpDDInfo->maCursor.Hide();
+ mpImpl->mpDDInfo->mbVisCursor = FALSE;
+ }
+}
+
+void TextView::ImpShowDDCursor()
+{
+ if ( !mpImpl->mpDDInfo->mbVisCursor )
+ {
+ Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, 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 = TRUE;
+ }
+}
+
+void TextView::SetPaintSelection( BOOL bPaint )
+{
+ if ( bPaint != mpImpl->mbPaintSelection )
+ {
+ mpImpl->mbPaintSelection = bPaint;
+ ShowSelection( mpImpl->maSelection );
+ }
+}
+
+void TextView::SetHighlightSelection( BOOL bSelectByHighlight )
+{
+ if ( bSelectByHighlight != mpImpl->mbHighlightSelection )
+ {
+ // Falls umschalten zwischendurch moeglich...
+ mpImpl->mbHighlightSelection = bSelectByHighlight;
+ }
+}
+
+BOOL TextView::Read( SvStream& rInput )
+{
+ BOOL bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection );
+ ShowCursor();
+ return bDone;
+}
+
+BOOL TextView::Write( SvStream& rOutput )
+{
+ return mpImpl->mpTextEngine->Read( rOutput, &mpImpl->maSelection );
+}
+
+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;
+ }
+
+ ULONG nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen();
+ // 0 means unlimited, there is just the String API limit handled above
+ if( nMaxLen != 0 )
+ {
+ ULONG nCurLen = mpImpl->mpTextEngine->GetTextLen();
+
+ sal_uInt32 nNewLen = rNewText.getLength();
+ if ( nCurLen + nNewLen > nMaxLen )
+ {
+ // see how much text will be replaced
+ 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;
+}
+
+BOOL TextView::ImplCheckTextLen( const String& rNewText )
+{
+ BOOL bOK = TRUE;
+ if ( mpImpl->mpTextEngine->GetMaxTextLen() )
+ {
+ 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() )
+ {
+ // 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;
+}
+
+void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ if ( mpImpl->mbClickedInSelection )
+ {
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" );
+
+ delete mpImpl->mpDDInfo;
+ mpImpl->mpDDInfo = new TextDDInfo;
+ mpImpl->mpDDInfo->mbStarterOfDD = TRUE;
+
+ TETextDataObject* pDataObj = new TETextDataObject( GetSelected() );
+
+ if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML
+ mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, 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)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ BOOL bChanges = FALSE;
+ if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo )
+ {
+ ImpHideDDCursor();
+
+ // Daten fuer das loeschen nach einem DROP_MOVE:
+ TextSelection aPrevSel( mpImpl->maSelection );
+ aPrevSel.Justify();
+ ULONG nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount();
+ USHORT nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() );
+
+ BOOL bStarterOfDD = FALSE;
+ for ( USHORT nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; )
+ bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : FALSE;
+
+ HideSelection();
+ ImpSetSelection( mpImpl->mpDDInfo->maDropPos );
+
+ mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DRAGANDDROP );
+
+ 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 = aOUString;
+ aText.ConvertLineEnd( 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(), 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() ) ) )
+ {
+ ULONG nNewParasBeforeSelection =
+ mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount;
+
+ aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection;
+ aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection;
+
+ if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() )
+ {
+ USHORT 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( TEXTUNDO_DRAGANDDROP );
+
+ 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)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+ ImpHideDDCursor();
+}
+
+void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
+{
+ vos::OGuard aVclGuard( Application::GetSolarMutex() );
+
+ 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 );
+
+/*
+ Size aOutSize = mpImpl->mpWindow->GetOutputSizePixel();
+ if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) ||
+ ( aMousePos.Y() < 0 ) || ( aMousePos.Y() > aOutSize.Height() ) )
+ {
+ // Scroll?
+ // No, I will not receive events for this...
+ }
+*/
+
+ 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(), FALSE );
+ if( mpImpl->mbCursorAtEndOfLine )
+ --nLineNo;
+ }
+ return nLineNo;
+}
+
+
+// -------------------------------------------------------------------------
+// (+) class TextSelFunctionSet
+// -------------------------------------------------------------------------
+TextSelFunctionSet::TextSelFunctionSet( TextView* pView )
+{
+ mpView = pView;
+}
+
+void __EXPORT TextSelFunctionSet::BeginDrag()
+{
+}
+
+void __EXPORT 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() );
+}
+
+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
+}
+TextEngine* TextView::GetTextEngine() const
+{ return mpImpl->mpTextEngine; }
+Window* TextView::GetWindow() const
+{ return mpImpl->mpWindow; }
+void TextView::EnableCursor( BOOL bEnable )
+{ mpImpl->mbCursorEnabled = bEnable; }
+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( BOOL bAutoIndent )
+{ mpImpl->mbAutoIndent = bAutoIndent; }
+BOOL TextView::IsAutoIndentMode() const
+{ return mpImpl->mbAutoIndent; }
+BOOL TextView::IsReadOnly() const
+{ return mpImpl->mbReadOnly; }
+void TextView::SetAutoScroll( BOOL bAutoScroll )
+{ mpImpl->mbAutoScroll = bAutoScroll; }
+BOOL TextView::IsAutoScroll() const
+{ return mpImpl->mbAutoScroll; }
+BOOL TextView::IsPaintSelection() const
+{ return mpImpl->mbPaintSelection; }
+BOOL TextView::IsHighlightSelection() const
+{ return mpImpl->mbHighlightSelection; }
+BOOL TextView::HasSelection() const
+{ return mpImpl->maSelection.HasRange(); }
+BOOL TextView::IsInsertMode() const
+{ return mpImpl->mbInsertMode; }
+void TextView::SupportProtectAttribute(sal_Bool bSupport)
+{ mpImpl->mbSupportProtectAttribute = bSupport;}
+
diff --git a/svtools/source/edit/textwindowpeer.cxx b/svtools/source/edit/textwindowpeer.cxx
new file mode 100644
index 000000000000..7f31e95c75a7
--- /dev/null
+++ b/svtools/source/edit/textwindowpeer.cxx
@@ -0,0 +1,59 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/textwindowpeer.hxx>
+#include <svtools/textview.hxx>
+#include "svtaccessiblefactory.hxx"
+
+namespace css = ::com::sun::star;
+
+namespace svt
+{
+ TextWindowPeer::TextWindowPeer(::TextView & rView, bool bCompoundControlChild):
+ m_rEngine(*rView.GetTextEngine()), m_rView(rView), m_bCompoundControlChild(bCompoundControlChild)
+ {
+ SetWindow(rView.GetWindow());
+ m_pFactoryAccess.reset( new AccessibleFactoryAccess );
+ }
+
+ // virtual
+ TextWindowPeer::~TextWindowPeer()
+ {
+ }
+
+ ::css::uno::Reference< ::css::accessibility::XAccessibleContext > TextWindowPeer::CreateAccessibleContext()
+ {
+ return m_pFactoryAccess->getFactory().createAccessibleTextWindowContext(
+ this, m_rEngine, m_rView, m_bCompoundControlChild
+ );
+ }
+}
diff --git a/svtools/source/edit/txtattr.cxx b/svtools/source/edit/txtattr.cxx
new file mode 100644
index 000000000000..e7466cbe1d85
--- /dev/null
+++ b/svtools/source/edit/txtattr.cxx
@@ -0,0 +1,197 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <txtattr.hxx>
+#include <vcl/font.hxx>
+
+
+
+
+TextAttrib::~TextAttrib()
+{
+}
+
+void TextAttrib::SetFont( Font& ) const
+{
+}
+
+TextAttrib* TextAttrib::Clone() const
+{
+ return NULL;
+}
+
+int TextAttrib::operator==( const TextAttrib& rAttr ) const
+{
+ return mnWhich == rAttr.mnWhich;
+}
+
+
+TextAttribFontColor::TextAttribFontColor( const Color& rColor )
+ : TextAttrib( TEXTATTR_FONTCOLOR ), maColor( rColor )
+{
+}
+
+TextAttribFontColor::TextAttribFontColor( const TextAttribFontColor& rAttr )
+ : TextAttrib( rAttr ), maColor( rAttr.maColor )
+{
+}
+
+TextAttribFontColor::~TextAttribFontColor()
+{
+}
+
+void TextAttribFontColor::SetFont( Font& rFont ) const
+{
+ rFont.SetColor( maColor );
+}
+
+TextAttrib* TextAttribFontColor::Clone() const
+{
+ return new TextAttribFontColor( *this );
+}
+
+int TextAttribFontColor::operator==( const TextAttrib& rAttr ) const
+{
+ return ( ( TextAttrib::operator==(rAttr ) ) &&
+ ( maColor == ((const TextAttribFontColor&)rAttr).maColor ) );
+}
+
+TextAttribFontWeight::TextAttribFontWeight( FontWeight eWeight )
+ : TextAttrib( TEXTATTR_FONTWEIGHT ), meWeight( eWeight )
+{
+}
+
+TextAttribFontWeight::TextAttribFontWeight( const TextAttribFontWeight& rAttr )
+ : TextAttrib( rAttr ), meWeight( rAttr.meWeight )
+{
+}
+
+TextAttribFontWeight::~TextAttribFontWeight()
+{
+}
+
+void TextAttribFontWeight::SetFont( Font& rFont ) const
+{
+ rFont.SetWeight( meWeight );
+}
+
+TextAttrib* TextAttribFontWeight::Clone() const
+{
+ return new TextAttribFontWeight( *this );
+}
+
+int TextAttribFontWeight::operator==( const TextAttrib& rAttr ) const
+{
+ return ( ( TextAttrib::operator==(rAttr ) ) &&
+ ( meWeight == ((const TextAttribFontWeight&)rAttr).meWeight ) );
+}
+
+
+TextAttribHyperLink::TextAttribHyperLink( const XubString& rURL )
+ : TextAttrib( TEXTATTR_HYPERLINK ), maURL( rURL )
+{
+ maColor = COL_BLUE;
+}
+
+TextAttribHyperLink::TextAttribHyperLink( const XubString& rURL, const XubString& rDescription )
+ : TextAttrib( TEXTATTR_HYPERLINK ), maURL( rURL ), maDescription( rDescription )
+{
+ maColor = COL_BLUE;
+}
+
+TextAttribHyperLink::TextAttribHyperLink( const TextAttribHyperLink& rAttr )
+ : TextAttrib( rAttr ), maURL( rAttr.maURL ), maDescription( rAttr.maDescription )
+{
+ maColor = rAttr.maColor;
+}
+
+TextAttribHyperLink::~TextAttribHyperLink()
+{
+}
+
+void TextAttribHyperLink::SetFont( Font& rFont ) const
+{
+ rFont.SetColor( maColor );
+ rFont.SetUnderline( UNDERLINE_SINGLE );
+}
+
+TextAttrib* TextAttribHyperLink::Clone() const
+{
+ return new TextAttribHyperLink( *this );
+}
+
+int TextAttribHyperLink::operator==( const TextAttrib& rAttr ) const
+{
+ return ( ( TextAttrib::operator==(rAttr ) ) &&
+ ( maURL == ((const TextAttribHyperLink&)rAttr).maURL ) &&
+ ( maDescription == ((const TextAttribHyperLink&)rAttr).maDescription ) &&
+ ( maColor == ((const TextAttribHyperLink&)rAttr).maColor ) );
+}
+
+/*-- 24.06.2004 14:49:44---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+TextAttribProtect::TextAttribProtect() :
+ TextAttrib( TEXTATTR_PROTECTED )
+{
+}
+/*-- 24.06.2004 14:49:44---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+TextAttribProtect::TextAttribProtect( const TextAttribProtect&) :
+ TextAttrib( TEXTATTR_PROTECTED )
+{
+}
+/*-- 24.06.2004 14:49:44---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+TextAttribProtect::~TextAttribProtect()
+{
+}
+/*-- 24.06.2004 14:49:44---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+void TextAttribProtect::SetFont( Font& ) const
+{
+}
+/*-- 24.06.2004 14:49:44---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+TextAttrib* TextAttribProtect::Clone() const
+{
+ return new TextAttribProtect();
+}
+/*-- 24.06.2004 14:49:45---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+int TextAttribProtect::operator==( const TextAttrib& rAttr ) const
+{
+ return ( TextAttrib::operator==(rAttr ) );
+}
diff --git a/svtools/source/edit/xtextedt.cxx b/svtools/source/edit/xtextedt.cxx
new file mode 100644
index 000000000000..0a4907edcadd
--- /dev/null
+++ b/svtools/source/edit/xtextedt.cxx
@@ -0,0 +1,421 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include <svtools/xtextedt.hxx>
+#include <vcl/svapp.hxx> // International
+#include <unotools/textsearch.hxx>
+#include <com/sun/star/util/SearchOptions.hpp>
+#include <com/sun/star/util/SearchFlags.hpp>
+
+using namespace ::com::sun::star;
+
+
+
+ // -------------------------------------------------------------------------
+// class ExtTextEngine
+// -------------------------------------------------------------------------
+ExtTextEngine::ExtTextEngine() : maGroupChars( String::CreateFromAscii( "(){}[]", 6 ) )
+{
+}
+
+ExtTextEngine::~ExtTextEngine()
+{
+}
+
+TextSelection ExtTextEngine::MatchGroup( const TextPaM& rCursor ) const
+{
+ TextSelection aSel( rCursor );
+ USHORT nPos = rCursor.GetIndex();
+ ULONG nPara = rCursor.GetPara();
+ ULONG nParas = GetParagraphCount();
+ if ( ( nPara < nParas ) && ( nPos < GetTextLen( nPara ) ) )
+ {
+ USHORT nMatchChar = maGroupChars.Search( GetText( rCursor.GetPara() ).GetChar( nPos ) );
+ if ( nMatchChar != STRING_NOTFOUND )
+ {
+ if ( ( nMatchChar % 2 ) == 0 )
+ {
+ // Vorwaerts suchen...
+ sal_Unicode nSC = maGroupChars.GetChar( nMatchChar );
+ sal_Unicode nEC = maGroupChars.GetChar( nMatchChar+1 );
+
+ USHORT nCur = nPos+1;
+ USHORT nLevel = 1;
+ while ( nLevel && ( nPara < nParas ) )
+ {
+ XubString aStr = GetText( nPara );
+ while ( nCur < aStr.Len() )
+ {
+ if ( aStr.GetChar( nCur ) == nSC )
+ nLevel++;
+ else if ( aStr.GetChar( nCur ) == nEC )
+ {
+ nLevel--;
+ if ( !nLevel )
+ break; // while nCur...
+ }
+ nCur++;
+ }
+
+ if ( nLevel )
+ {
+ nPara++;
+ nCur = 0;
+ }
+ }
+ if ( nLevel == 0 ) // gefunden
+ {
+ aSel.GetStart() = rCursor;
+ aSel.GetEnd() = TextPaM( nPara, nCur+1 );
+ }
+ }
+ else
+ {
+ // Rueckwaerts suchen...
+ xub_Unicode nEC = maGroupChars.GetChar( nMatchChar );
+ xub_Unicode nSC = maGroupChars.GetChar( nMatchChar-1 );
+
+ USHORT nCur = rCursor.GetIndex()-1;
+ USHORT nLevel = 1;
+ while ( nLevel )
+ {
+ if ( GetTextLen( nPara ) )
+ {
+ XubString aStr = GetText( nPara );
+ while ( nCur )
+ {
+ if ( aStr.GetChar( nCur ) == nSC )
+ {
+ nLevel--;
+ if ( !nLevel )
+ break; // while nCur...
+ }
+ else if ( aStr.GetChar( nCur ) == nEC )
+ nLevel++;
+
+ nCur--;
+ }
+ }
+
+ if ( nLevel )
+ {
+ if ( nPara )
+ {
+ nPara--;
+ nCur = GetTextLen( nPara )-1; // egal ob negativ, weil if Len()
+ }
+ else
+ break;
+ }
+ }
+
+ if ( nLevel == 0 ) // gefunden
+ {
+ aSel.GetStart() = rCursor;
+ aSel.GetStart().GetIndex()++; // hinter das Zeichen
+ aSel.GetEnd() = TextPaM( nPara, nCur );
+ }
+ }
+ }
+ }
+ return aSel;
+}
+
+BOOL ExtTextEngine::Search( TextSelection& rSel, const util::SearchOptions& rSearchOptions, BOOL bForward )
+{
+ TextSelection aSel( rSel );
+ aSel.Justify();
+
+ BOOL bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) );
+
+ TextPaM aStartPaM( aSel.GetEnd() );
+ if ( aSel.HasRange() && ( ( bSearchInSelection && bForward ) || ( !bSearchInSelection && !bForward ) ) )
+ {
+ aStartPaM = aSel.GetStart();
+ }
+
+ bool bFound = false;
+ ULONG nStartNode, nEndNode;
+
+ if ( bSearchInSelection )
+ nEndNode = bForward ? aSel.GetEnd().GetPara() : aSel.GetStart().GetPara();
+ else
+ nEndNode = bForward ? (GetParagraphCount()-1) : 0;
+
+ nStartNode = aStartPaM.GetPara();
+
+ util::SearchOptions aOptions( rSearchOptions );
+ aOptions.Locale = Application::GetSettings().GetLocale();
+ utl::TextSearch aSearcher( rSearchOptions );
+
+ // ueber die Absaetze iterieren...
+ for ( ULONG nNode = nStartNode;
+ bForward ? ( nNode <= nEndNode) : ( nNode >= nEndNode );
+ bForward ? nNode++ : nNode-- )
+ {
+ String aText = GetText( nNode );
+ USHORT nStartPos = 0;
+ USHORT nEndPos = aText.Len();
+ if ( nNode == nStartNode )
+ {
+ if ( bForward )
+ nStartPos = aStartPaM.GetIndex();
+ else
+ nEndPos = aStartPaM.GetIndex();
+ }
+ if ( ( nNode == nEndNode ) && bSearchInSelection )
+ {
+ if ( bForward )
+ nEndPos = aSel.GetEnd().GetIndex();
+ else
+ nStartPos = aSel.GetStart().GetIndex();
+ }
+
+ if ( bForward )
+ bFound = aSearcher.SearchFrwrd( aText, &nStartPos, &nEndPos );
+ else
+ bFound = aSearcher.SearchBkwrd( aText, &nEndPos, &nStartPos );
+
+ if ( bFound )
+ {
+ rSel.GetStart().GetPara() = nNode;
+ rSel.GetStart().GetIndex() = nStartPos;
+ rSel.GetEnd().GetPara() = nNode;
+ rSel.GetEnd().GetIndex() = nEndPos;
+ // Ueber den Absatz selektieren?
+ // Select over the paragraph?
+ // FIXME This should be max long...
+ if( nEndPos == sal::static_int_cast<USHORT>(-1) ) // USHORT for 0 and -1 !
+ {
+ if ( (rSel.GetEnd().GetPara()+1) < GetParagraphCount() )
+ {
+ rSel.GetEnd().GetPara()++;
+ rSel.GetEnd().GetIndex() = 0;
+ }
+ else
+ {
+ rSel.GetEnd().GetIndex() = nStartPos;
+ bFound = false;
+ }
+ }
+
+ break;
+ }
+
+ if ( !bForward && !nNode ) // Bei rueckwaertsuche, wenn nEndNode = 0:
+ break;
+ }
+
+ return bFound;
+}
+
+
+ // -------------------------------------------------------------------------
+// class ExtTextView
+// -------------------------------------------------------------------------
+ExtTextView::ExtTextView( ExtTextEngine* pEng, Window* pWindow )
+ : TextView( pEng, pWindow )
+{
+}
+
+ExtTextView::~ExtTextView()
+{
+}
+
+BOOL ExtTextView::MatchGroup()
+{
+ TextSelection aTmpSel( GetSelection() );
+ aTmpSel.Justify();
+ if ( ( aTmpSel.GetStart().GetPara() != aTmpSel.GetEnd().GetPara() ) ||
+ ( ( aTmpSel.GetEnd().GetIndex() - aTmpSel.GetStart().GetIndex() ) > 1 ) )
+ {
+ return FALSE;
+ }
+
+ TextSelection aMatchSel = ((ExtTextEngine*)GetTextEngine())->MatchGroup( aTmpSel.GetStart() );
+ if ( aMatchSel.HasRange() )
+ SetSelection( aMatchSel );
+
+ return aMatchSel.HasRange() ? TRUE : FALSE;
+}
+
+BOOL ExtTextView::Search( const util::SearchOptions& rSearchOptions, BOOL bForward )
+{
+ BOOL bFound = FALSE;
+ TextSelection aSel( GetSelection() );
+ if ( ((ExtTextEngine*)GetTextEngine())->Search( aSel, rSearchOptions, bForward ) )
+ {
+ bFound = TRUE;
+ // Erstmal den Anfang des Wortes als Selektion einstellen,
+ // damit das ganze Wort in den sichtbaren Bereich kommt.
+ SetSelection( aSel.GetStart() );
+ ShowCursor( TRUE, FALSE );
+ }
+ else
+ {
+ aSel = GetSelection().GetEnd();
+ }
+
+ SetSelection( aSel );
+ ShowCursor();
+
+ return bFound;
+}
+
+USHORT ExtTextView::Replace( const util::SearchOptions& rSearchOptions, BOOL bAll, BOOL bForward )
+{
+ USHORT nFound = 0;
+
+ if ( !bAll )
+ {
+ if ( GetSelection().HasRange() )
+ {
+ InsertText( rSearchOptions.replaceString );
+ nFound = 1;
+ Search( rSearchOptions, bForward ); // gleich zum naechsten
+ }
+ else
+ {
+ if( Search( rSearchOptions, bForward ) )
+ nFound = 1;
+ }
+ }
+ else
+ {
+ // Der Writer ersetzt alle, vom Anfang bis Ende...
+
+ ExtTextEngine* pTextEngine = (ExtTextEngine*)GetTextEngine();
+
+ // HideSelection();
+ TextSelection aSel;
+
+ BOOL bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) );
+ if ( bSearchInSelection )
+ {
+ aSel = GetSelection();
+ aSel.Justify();
+ }
+
+ TextSelection aSearchSel( aSel );
+
+ BOOL bFound = pTextEngine->Search( aSel, rSearchOptions, TRUE );
+ if ( bFound )
+ pTextEngine->UndoActionStart( XTEXTUNDO_REPLACEALL );
+ while ( bFound )
+ {
+ nFound++;
+
+ TextPaM aNewStart = pTextEngine->ImpInsertText( aSel, rSearchOptions.replaceString );
+ aSel = aSearchSel;
+ aSel.GetStart() = aNewStart;
+ bFound = pTextEngine->Search( aSel, rSearchOptions, TRUE );
+ }
+ if ( nFound )
+ {
+ SetSelection( aSel.GetStart() );
+ pTextEngine->FormatAndUpdate( this );
+ pTextEngine->UndoActionEnd( XTEXTUNDO_REPLACEALL );
+ }
+ }
+ return nFound;
+}
+
+BOOL ExtTextView::ImpIndentBlock( BOOL bRight )
+{
+ BOOL bDone = FALSE;
+
+ TextSelection aSel = GetSelection();
+ aSel.Justify();
+
+ HideSelection();
+ GetTextEngine()->UndoActionStart( bRight ? XTEXTUNDO_INDENTBLOCK : XTEXTUNDO_UNINDENTBLOCK );
+
+ ULONG nStartPara = aSel.GetStart().GetPara();
+ ULONG nEndPara = aSel.GetEnd().GetPara();
+ if ( aSel.HasRange() && !aSel.GetEnd().GetIndex() )
+ {
+ nEndPara--; // den dann nicht einruecken...
+ }
+
+ for ( ULONG nPara = nStartPara; nPara <= nEndPara; nPara++ )
+ {
+ if ( bRight )
+ {
+ // Tabs hinzufuegen
+ GetTextEngine()->ImpInsertText( TextPaM( nPara, 0 ), '\t' );
+ bDone = TRUE;
+ }
+ else
+ {
+ // Tabs/Blanks entfernen
+ String aText = GetTextEngine()->GetText( nPara );
+ if ( aText.Len() && (
+ ( aText.GetChar( 0 ) == '\t' ) ||
+ ( aText.GetChar( 0 ) == ' ' ) ) )
+ {
+ GetTextEngine()->ImpDeleteText( TextSelection( TextPaM( nPara, 0 ), TextPaM( nPara, 1 ) ) );
+ bDone = TRUE;
+ }
+ }
+ }
+
+ GetTextEngine()->UndoActionEnd( bRight ? XTEXTUNDO_INDENTBLOCK : XTEXTUNDO_UNINDENTBLOCK );
+
+ BOOL bRange = aSel.HasRange();
+ if ( bRight )
+ {
+ aSel.GetStart().GetIndex()++;
+ if ( bRange && ( aSel.GetEnd().GetPara() == nEndPara ) )
+ aSel.GetEnd().GetIndex()++;
+ }
+ else
+ {
+ if ( aSel.GetStart().GetIndex() )
+ aSel.GetStart().GetIndex()--;
+ if ( bRange && aSel.GetEnd().GetIndex() )
+ aSel.GetEnd().GetIndex()--;
+ }
+
+ ImpSetSelection( aSel );
+ GetTextEngine()->FormatAndUpdate( this );
+
+ return bDone;
+}
+
+BOOL ExtTextView::IndentBlock()
+{
+ return ImpIndentBlock( TRUE );
+}
+
+BOOL ExtTextView::UnindentBlock()
+{
+ return ImpIndentBlock( FALSE );
+}
+