913 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			913 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*************************************************************************
 | ||
|  *
 | ||
|  *  $RCSfile: textedit.cxx,v $
 | ||
|  *
 | ||
|  *  $Revision: 1.12 $
 | ||
|  *
 | ||
|  *  last change: $Author: vg $ $Date: 2004-01-06 19:40:35 $
 | ||
|  *
 | ||
|  *  The Contents of this file are made available subject to the terms of
 | ||
|  *  either of the following licenses
 | ||
|  *
 | ||
|  *         - GNU Lesser General Public License Version 2.1
 | ||
|  *         - Sun Industry Standards Source License Version 1.1
 | ||
|  *
 | ||
|  *  Sun Microsystems Inc., October, 2000
 | ||
|  *
 | ||
|  *  GNU Lesser General Public License Version 2.1
 | ||
|  *  =============================================
 | ||
|  *  Copyright 2000 by Sun Microsystems, Inc.
 | ||
|  *  901 San Antonio Road, Palo Alto, CA 94303, USA
 | ||
|  *
 | ||
|  *  This library is free software; you can redistribute it and/or
 | ||
|  *  modify it under the terms of the GNU Lesser General Public
 | ||
|  *  License version 2.1, as published by the Free Software Foundation.
 | ||
|  *
 | ||
|  *  This library is distributed in the hope that it will be useful,
 | ||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | ||
|  *  Lesser General Public License for more details.
 | ||
|  *
 | ||
|  *  You should have received a copy of the GNU Lesser General Public
 | ||
|  *  License along with this library; if not, write to the Free Software
 | ||
|  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | ||
|  *  MA  02111-1307  USA
 | ||
|  *
 | ||
|  *
 | ||
|  *  Sun Industry Standards Source License Version 1.1
 | ||
|  *  =================================================
 | ||
|  *  The contents of this file are subject to the Sun Industry Standards
 | ||
|  *  Source License Version 1.1 (the "License"); You may not use this file
 | ||
|  *  except in compliance with the License. You may obtain a copy of the
 | ||
|  *  License at http://www.openoffice.org/license.html.
 | ||
|  *
 | ||
|  *  Software provided under this License is provided on an "AS IS" basis,
 | ||
|  *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 | ||
|  *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 | ||
|  *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 | ||
|  *  See the License for the specific provisions governing your rights and
 | ||
|  *  obligations concerning the Software.
 | ||
|  *
 | ||
|  *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 | ||
|  *
 | ||
|  *  Copyright: 2000 by Sun Microsystems, Inc.
 | ||
|  *
 | ||
|  *  All Rights Reserved.
 | ||
|  *
 | ||
|  *  Contributor(s): _______________________________________
 | ||
|  *
 | ||
|  *
 | ||
|  ************************************************************************/
 | ||
| 
 | ||
| #ifndef _STREAM_HXX //autogen
 | ||
| #include <tools/stream.hxx>
 | ||
| #endif
 | ||
| 
 | ||
| #ifndef _TEXTENG_HXX //autogen
 | ||
| #include <svtools/texteng.hxx>
 | ||
| #endif
 | ||
| #ifndef _TEXTVIEW_HXX //autogen
 | ||
| #include <svtools/textview.hxx>
 | ||
| #endif
 | ||
| #ifndef _TXTATTR_HXX //autogen
 | ||
| #include <svtools/txtattr.hxx>
 | ||
| #endif
 | ||
| #ifndef __SBX_SBXMETHOD_HXX //autogen
 | ||
| #include <svtools/sbxmeth.hxx>
 | ||
| #endif
 | ||
| #ifndef _BASIC_TTRESHLP_HXX
 | ||
| #include "ttstrhlp.hxx"
 | ||
| #endif
 | ||
| 
 | ||
| #include "basic.hrc"
 | ||
| #include "textedit.hxx"
 | ||
| #include "appedit.hxx"
 | ||
| #include "brkpnts.hxx"
 | ||
| #include "testtool.hxx"     // defines f<>r das Syntaxhighlighting
 | ||
| 
 | ||
| TextEditImp::TextEditImp( AppEdit* pParent, const WinBits& aBits )
 | ||
| : Window( pParent, aBits )
 | ||
| , pAppEdit( pParent )
 | ||
| , bHighlightning( FALSE )
 | ||
| , bDoSyntaxHighlight( FALSE )
 | ||
| , bDelayHighlight( TRUE )
 | ||
| , nTipId( 0 )
 | ||
| , bViewMoved( FALSE )
 | ||
| {
 | ||
|     pTextEngine = new TextEngine();
 | ||
|     pTextEngine->SetMaxTextLen( STRING_MAXLEN );
 | ||
|     pTextEngine->EnableUndo( TRUE );
 | ||
| 
 | ||
|     pTextView = new TextView( pTextEngine, this );
 | ||
|     pTextEngine->InsertView( pTextView );
 | ||
|     pTextEngine->SetModified( FALSE );
 | ||
| 
 | ||
|     aSyntaxIdleTimer.SetTimeout( 200 );
 | ||
|     aSyntaxIdleTimer.SetTimeoutHdl( LINK( this, TextEditImp, SyntaxTimerHdl ) );
 | ||
| 
 | ||
|     aImplSyntaxIdleTimer.SetTimeout( 1 );
 | ||
|     aImplSyntaxIdleTimer.SetTimeoutHdl( LINK( this, TextEditImp, SyntaxTimerHdl ) );
 | ||
| 
 | ||
|     StartListening( *pTextEngine );
 | ||
| 
 | ||
|     HideTipTimer.SetTimeout( 5000 );    // 5 Sekunden
 | ||
|     ShowTipTimer.SetTimeout( 500 );     // 1/2 Sekunde
 | ||
|     HideTipTimer.SetTimeoutHdl( LINK( this, TextEditImp, HideVarContents ) );
 | ||
|     ShowTipTimer.SetTimeoutHdl( LINK( this, TextEditImp, ShowVarContents ) );
 | ||
| }
 | ||
| 
 | ||
| TextEditImp::~TextEditImp()
 | ||
| {
 | ||
|     pTextEngine->RemoveView( pTextView );
 | ||
|     delete pTextView;
 | ||
|     delete pTextEngine;
 | ||
| }
 | ||
| 
 | ||
| BOOL TextEditImp::ViewMoved()
 | ||
| {
 | ||
|     BOOL bOld = bViewMoved;
 | ||
|     bViewMoved = FALSE;
 | ||
|     return bOld;
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
 | ||
| {
 | ||
|     if ( rHint.ISA( TextHint ) )
 | ||
|     {
 | ||
|         const TextHint& rTextHint = (const TextHint&)rHint;
 | ||
|         if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED )
 | ||
|         {
 | ||
|             pAppEdit->pHScroll->SetThumbPos( pTextView->GetStartDocPos().X() );
 | ||
|             pAppEdit->pVScroll->SetThumbPos( pTextView->GetStartDocPos().Y() );
 | ||
|             if ( ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow() )
 | ||
|                 ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow()->Scroll( 0, ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow()->GetCurYOffset() - pTextView->GetStartDocPos().Y() );
 | ||
|             bViewMoved = TRUE;
 | ||
|         }
 | ||
|         else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED )
 | ||
|         {
 | ||
|             if ( pTextView->GetStartDocPos().Y() )
 | ||
|             {
 | ||
|                 long nOutHeight = GetOutputSizePixel().Height();
 | ||
|                 long nTextHeight = pTextEngine->GetTextHeight();
 | ||
|                 if ( nTextHeight < nOutHeight )
 | ||
|                     pTextView->Scroll( 0, pTextView->GetStartDocPos().Y() );
 | ||
|             }
 | ||
| 
 | ||
|             pAppEdit->SetScrollBarRanges();
 | ||
|         }
 | ||
|         else if( rTextHint.GetId() == TEXT_HINT_TEXTFORMATTED )
 | ||
|         {
 | ||
|             ULONG nWidth = pTextEngine->CalcTextWidth();
 | ||
|             if ( (ULONG)nWidth != pAppEdit->nCurTextWidth )
 | ||
|             {
 | ||
|                 pAppEdit->nCurTextWidth = nWidth;
 | ||
|                 if ( pAppEdit->pHScroll )
 | ||
|                 {   // Initialisierung abgeschlossen?
 | ||
|                     pAppEdit->pHScroll->SetRange( Range( 0, (long)nWidth) );
 | ||
|                     pAppEdit->pHScroll->SetThumbPos( pTextView->GetStartDocPos().X() );
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|         else if( rTextHint.GetId() == TEXT_HINT_PARAINSERTED )
 | ||
|         {
 | ||
|             if ( ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow() )
 | ||
|                 ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow()->AdjustBreakpoints( rTextHint.GetValue()+1, TRUE );
 | ||
| 
 | ||
|             // L<>stiges anpassen f<>r 2 Zeichen am Zeilenende statt einem(Hartverdrateter Default)
 | ||
|             pTextEngine->SetMaxTextLen( STRING_MAXLEN - pTextEngine->GetParagraphCount() );
 | ||
|         }
 | ||
|         else if( rTextHint.GetId() == TEXT_HINT_PARAREMOVED )
 | ||
|         {
 | ||
|             if ( ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow() )
 | ||
|                 ((TextEdit*)(pAppEdit->pDataEdit))->GetBreakpointWindow()->AdjustBreakpoints( rTextHint.GetValue()+1, FALSE );
 | ||
| 
 | ||
|             // L<>stiges anpassen f<>r 2 Zeichen am Zeilenende statt einem(Hartverdrateter Default)
 | ||
|             pTextEngine->SetMaxTextLen( STRING_MAXLEN - pTextEngine->GetParagraphCount() );
 | ||
|         }
 | ||
|         else if( rTextHint.GetId() == TEXT_HINT_FORMATPARA )
 | ||
|         {
 | ||
|             DoDelayedSyntaxHighlight( rTextHint.GetValue() );
 | ||
|             if ( pTextView->GetTextEngine()->IsModified() )
 | ||
|                 ModifyHdl.Call( NULL );
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| #define TEXTATTR_SPECHIAL   55
 | ||
| class TextAttribSpechial : public TextAttrib
 | ||
| {
 | ||
| private:
 | ||
|     FontWeight  maFontWeight;
 | ||
| 
 | ||
| public:
 | ||
|                             TextAttribSpechial( const FontWeight& rFontWeight );
 | ||
|                             TextAttribSpechial( const TextAttribSpechial& rAttr );
 | ||
|                             ~TextAttribSpechial() {;}
 | ||
| 
 | ||
|     virtual void            SetFont( Font& rFont ) const;
 | ||
|     virtual TextAttrib*     Clone() const;
 | ||
|     virtual int             operator==( const TextAttrib& rAttr ) const;
 | ||
| };
 | ||
| 
 | ||
| TextAttribSpechial::TextAttribSpechial( const FontWeight& rFontWeight )
 | ||
|     : TextAttrib( TEXTATTR_SPECHIAL ), maFontWeight( rFontWeight )
 | ||
| {}
 | ||
| 
 | ||
| TextAttribSpechial::TextAttribSpechial( const TextAttribSpechial& rAttr )
 | ||
|     : TextAttrib( rAttr ), maFontWeight( rAttr.maFontWeight )
 | ||
| {}
 | ||
| 
 | ||
| void TextAttribSpechial::SetFont( Font& rFont ) const
 | ||
| {
 | ||
|     rFont.SetWeight( maFontWeight );
 | ||
| }
 | ||
| 
 | ||
| TextAttrib* TextAttribSpechial::Clone() const
 | ||
| {
 | ||
|     return new TextAttribSpechial( *this );
 | ||
| }
 | ||
| 
 | ||
| int TextAttribSpechial::operator==( const TextAttrib& rAttr ) const
 | ||
| {
 | ||
|     return ( ( TextAttrib::operator==(rAttr ) ) &&
 | ||
|                 ( maFontWeight == ((const TextAttribSpechial&)rAttr).maFontWeight ) );
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::ImpDoHighlight( const String& rSource, ULONG nLineOff )
 | ||
| {
 | ||
|     SbTextPortions aPortionList;
 | ||
|     pAppEdit->GetBasicFrame()->Basic().Highlight( rSource, aPortionList );
 | ||
| 
 | ||
|     USHORT nCount = aPortionList.Count();
 | ||
|     if ( !nCount )
 | ||
|         return;
 | ||
| 
 | ||
|     SbTextPortion& rLast = aPortionList[nCount-1];
 | ||
|     if ( rLast.nStart > rLast.nEnd )    // Nur bis Bug von MD behoben
 | ||
|     {
 | ||
| #if OSL_DEBUG_LEVEL > 1
 | ||
|         DBG_ERROR( "MD-Bug nicht beseitigt!" );
 | ||
| #endif
 | ||
|         nCount--;
 | ||
|         aPortionList.Remove( nCount);
 | ||
|         if ( !nCount )
 | ||
|             return;
 | ||
|     }
 | ||
| 
 | ||
|     /// hier werden die Type f<>r das Testtool nachbearbeitet
 | ||
|     USHORT i;
 | ||
|     BOOL bWasTTControl = FALSE;
 | ||
|     for ( i = 0; i < aPortionList.Count(); i++ )
 | ||
|     {
 | ||
|         SbTextPortion& r = aPortionList[i];
 | ||
| //      DBG_ASSERT( r.nStart <= r.nEnd, "Highlight: Start > End?" );
 | ||
|         if ( r.nStart > r.nEnd )    // Nur bis Bug von MD behoben
 | ||
|             continue;
 | ||
| 
 | ||
|         SbTextType eType = r.eType;
 | ||
|         Color aColor;
 | ||
|         switch ( eType )
 | ||
|         {
 | ||
|             case SB_SYMBOL:
 | ||
|                 {
 | ||
|                      String aSymbol = rSource.Copy( r.nStart, r.nEnd - r.nStart +1 );
 | ||
|                     r.eType = pAppEdit->GetBasicFrame()->Basic().GetSymbolType( aSymbol, bWasTTControl );
 | ||
| 
 | ||
|                     if ( r.eType == TT_CONTROL )
 | ||
|                         bWasTTControl = TRUE;
 | ||
|                     else
 | ||
|                         bWasTTControl = FALSE;
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SB_PUNCTUATION:
 | ||
|                 {
 | ||
|                      String aPunctuation = rSource.Copy( r.nStart, r.nEnd - r.nStart +1 );
 | ||
|                     if ( aPunctuation.CompareToAscii( "." ) != COMPARE_EQUAL )
 | ||
|                         bWasTTControl = FALSE;
 | ||
|                 }
 | ||
|                 break;
 | ||
|             default:
 | ||
|                 bWasTTControl = FALSE;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     // Evtl. Optimieren:
 | ||
|     // Wenn haufig gleiche Farbe, dazwischen Blank ohne Farbe,
 | ||
|     // ggf. zusammenfassen, oder zumindest das Blank,
 | ||
|     // damit weniger Attribute
 | ||
|     if ( TRUE /*bOptimizeHighlight*/ )
 | ||
|     {
 | ||
|         // Es muessen nur die Blanks und Tabs mit attributiert werden.
 | ||
|         // Wenn zwei gleiche Attribute hintereinander eingestellt werden,
 | ||
|         // optimiert das die EditEngine.
 | ||
|         xub_StrLen nLastEnd = 0;
 | ||
|         xub_StrLen nLine = aPortionList[0].nLine;
 | ||
|         for ( USHORT i = 0; i < nCount; i++ )
 | ||
|         {
 | ||
|             SbTextPortion& r = aPortionList[i];
 | ||
|             DBG_ASSERT( r.nLine == nLine, "doch mehrere Zeilen ?" );
 | ||
|             DBG_ASSERT( r.nStart <= r.nEnd, "Highlight: Start > End?" );
 | ||
|             if ( r.nStart > r.nEnd )    // Nur bis Bug von MD behoben
 | ||
|                 continue;
 | ||
| 
 | ||
|             if ( r.nStart > nLastEnd )
 | ||
|             {
 | ||
|                 // Kann ich mich drauf verlassen, dass alle ausser
 | ||
|                 // Blank und Tab gehighlightet wird ?!
 | ||
|                 r.nStart = nLastEnd;
 | ||
|             }
 | ||
|             nLastEnd = r.nEnd+1;
 | ||
|             if ( ( i == (nCount-1) ) && ( r.nEnd < rSource.Len() ) )
 | ||
|                 r.nEnd = rSource.Len()-1;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     BOOL bWasModified = pTextEngine->IsModified();
 | ||
|     for ( i = 0; i < aPortionList.Count(); i++ )
 | ||
|     {
 | ||
|         SbTextPortion& r = aPortionList[i];
 | ||
| //      DBG_ASSERT( r.nStart <= r.nEnd, "Highlight: Start > End?" );
 | ||
|         if ( r.nStart > r.nEnd )    // Nur bis Bug von MD behoben
 | ||
|             continue;
 | ||
| 
 | ||
|         SbTextType eCol = r.eType;
 | ||
|         Color aColor;
 | ||
|         xub_StrLen nLine = nLineOff+r.nLine-1; // -1, weil Basic bei 1 beginnt
 | ||
|         switch ( eCol )
 | ||
|         {
 | ||
|             case SB_KEYWORD:
 | ||
|                 aColor = Color( COL_BLUE );
 | ||
|                 break;
 | ||
|             case SB_SYMBOL:
 | ||
|                 aColor = Color( RGB_COLORDATA( 0x00, 0x60, 0x00 ) );
 | ||
|                 break;
 | ||
|             case SB_STRING:
 | ||
|                 aColor = Color( COL_RED );
 | ||
|                 break;
 | ||
|             case SB_NUMBER:
 | ||
|                 aColor = Color( COL_MAGENTA );
 | ||
|                 break;
 | ||
|             case SB_PUNCTUATION:
 | ||
|                 aColor = Color( COL_BLACK );
 | ||
|                 break;
 | ||
|             case SB_COMMENT:
 | ||
|                 aColor = Color( COL_GRAY );
 | ||
|                 break;
 | ||
|             case TT_KEYWORD:
 | ||
|             case TT_LOCALCMD:
 | ||
|                 aColor = Color( COL_LIGHTBLUE );
 | ||
|                 break;
 | ||
|             case TT_REMOTECMD:
 | ||
|                 aColor = Color( RGB_COLORDATA( 0x00, 0xB0, 0xB0 ) );
 | ||
|                 break;
 | ||
|             case TT_CONTROL:
 | ||
|             case TT_SLOT:
 | ||
|                 aColor = Color( RGB_COLORDATA( 0x00, 0xB0, 0x00 ) );
 | ||
|                 break;
 | ||
|             case TT_METHOD:
 | ||
|                 aColor = Color( RGB_COLORDATA( 0x00, 0xB0, 0x00 ) );
 | ||
|                 break;
 | ||
|             case TT_NOMETHOD:
 | ||
|                 {
 | ||
|                     aColor = Color( COL_RED );
 | ||
|                     pTextEngine->SetAttrib( TextAttribSpechial( WEIGHT_BOLD ), nLine, r.nStart, r.nEnd+1 );
 | ||
|                 }
 | ||
|                 break;
 | ||
|             default:
 | ||
|                 {
 | ||
|                     aColor = Color( RGB_COLORDATA( 0xff, 0x80, 0x80 ) );
 | ||
|                     DBG_ERROR( "Unbekannte Syntax-Farbe?" );
 | ||
|                 }
 | ||
|         }
 | ||
|         pTextEngine->SetAttrib( TextAttribFontColor( aColor ), nLine, r.nStart, r.nEnd+1 );
 | ||
|     }
 | ||
|     // Das Highlighten soll kein Modify setzen
 | ||
|     pTextEngine->SetModified( bWasModified );
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::DoSyntaxHighlight( ULONG nPara )
 | ||
| {
 | ||
|     // Durch das DelayedSyntaxHighlight kann es passieren,
 | ||
|     // dass die Zeile nicht mehr existiert!
 | ||
|     if ( nPara < pTextEngine->GetParagraphCount() )
 | ||
|     {
 | ||
|         // leider weis ich nicht, ob genau diese Zeile Modified() ...
 | ||
| //      if ( pProgress )
 | ||
| //          pProgress->StepProgress();
 | ||
|         pTextEngine->RemoveAttribs( nPara );
 | ||
|         String aSource( pTextEngine->GetText( nPara ) );
 | ||
|         ImpDoHighlight( aSource, nPara );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::DoDelayedSyntaxHighlight( xub_StrLen nPara )
 | ||
| {
 | ||
|     // Zeile wird nur in 'Liste' aufgenommen, im TimerHdl abgearbeitet.
 | ||
|     // => Nicht Absaetze manipulieren, waehrend EditEngine formatiert.
 | ||
| //  if ( pProgress )
 | ||
| //      pProgress->StepProgress();
 | ||
| 
 | ||
|     if ( !bHighlightning && bDoSyntaxHighlight )
 | ||
|     {
 | ||
|         if ( bDelayHighlight )
 | ||
|         {
 | ||
|             aSyntaxLineTable.Insert( nPara, (void*)(ULONG)1 );
 | ||
|             aSyntaxIdleTimer.Start();
 | ||
|         }
 | ||
|         else
 | ||
|             DoSyntaxHighlight( nPara );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| IMPL_LINK( TextEditImp, SyntaxTimerHdl, Timer *, EMPTYARG )
 | ||
| {
 | ||
|     DBG_ASSERT( pTextView, "Noch keine View, aber Syntax-Highlight ?!" );
 | ||
|     pTextEngine->SetUpdateMode( FALSE );
 | ||
| 
 | ||
|     bHighlightning = TRUE;
 | ||
|     USHORT nLine;
 | ||
|     while ( aSyntaxLineTable.First() && !Application::AnyInput( INPUT_MOUSEANDKEYBOARD ) )
 | ||
|     {
 | ||
|         nLine = (USHORT)aSyntaxLineTable.GetCurKey();
 | ||
|         DoSyntaxHighlight( nLine );
 | ||
|         aSyntaxLineTable.Remove( nLine );
 | ||
| /*      if ( Application::AnyInput() )
 | ||
|         {
 | ||
|             aSyntaxIdleTimer.Start();       // Starten, falls wir in einem Dialog landen
 | ||
|             pTextView->ShowCursor( TRUE, TRUE );
 | ||
|             pTextEngine->SetUpdateMode( TRUE );
 | ||
|             bHighlightning = FALSE;
 | ||
|             GetpApp()->Reschedule();
 | ||
|             bHighlightning = TRUE;
 | ||
|             pTextEngine->SetUpdateMode( FALSE );
 | ||
|         }*/
 | ||
|     }
 | ||
| 
 | ||
|     BOOL bWasModified = pTextEngine->IsModified();
 | ||
|     if ( aSyntaxLineTable.Count() > 3 )                 // Ohne VDev
 | ||
|     {
 | ||
|         pTextEngine->SetUpdateMode( TRUE );
 | ||
|         pTextView->ShowCursor( TRUE, TRUE );
 | ||
|     }
 | ||
|     else
 | ||
|         pTextEngine->SetUpdateMode( TRUE );             // ! Mit VDev
 | ||
| //  pTextView->ForceUpdate();
 | ||
| 
 | ||
|     // SetUpdateMode( TRUE ) soll kein Modify setzen
 | ||
|     pTextEngine->SetModified( bWasModified );
 | ||
| 
 | ||
|     // SyntaxTimerHdl wird gerufen, wenn Text-Aenderung
 | ||
|     // => gute Gelegenheit, Textbreite zu ermitteln!
 | ||
| //  long nPrevTextWidth = nCurTextWidth;
 | ||
| //  nCurTextWidth = pTextEngine->CalcTextWidth();
 | ||
| //  if ( nCurTextWidth != nPrevTextWidth )
 | ||
| //      SetScrollBarRanges();
 | ||
|     bHighlightning = FALSE;
 | ||
| 
 | ||
|     if ( aSyntaxLineTable.First() )
 | ||
|         aImplSyntaxIdleTimer.Start();
 | ||
| 
 | ||
| //  while ( Application::AnyInput() )
 | ||
| //      Application::Reschedule();  // Reschedule, da der UserEvent keine Paints etc. durchl<68>sst
 | ||
| 
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::InvalidateSyntaxHighlight()
 | ||
| {
 | ||
|     for ( xub_StrLen i = 0; i < pTextEngine->GetParagraphCount(); i++ )
 | ||
|         DoDelayedSyntaxHighlight( i );
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::SyntaxHighlight( BOOL bNew )
 | ||
| {
 | ||
|     if ( ( bNew && bDoSyntaxHighlight ) || ( !bNew && !bDoSyntaxHighlight ) )
 | ||
|         return;
 | ||
| 
 | ||
|     bDoSyntaxHighlight = bNew;
 | ||
|     if ( !pTextEngine )
 | ||
|         return;
 | ||
| 
 | ||
| 
 | ||
|     if ( bDoSyntaxHighlight )
 | ||
|     {
 | ||
|         InvalidateSyntaxHighlight();
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         aSyntaxIdleTimer.Stop();
 | ||
|         pTextEngine->SetUpdateMode( FALSE );
 | ||
|         for ( ULONG i = 0; i < pTextEngine->GetParagraphCount(); i++ )
 | ||
|             pTextEngine->RemoveAttribs( i );
 | ||
| 
 | ||
| //      pTextEngine->QuickFormatDoc();
 | ||
|         pTextEngine->SetUpdateMode( TRUE );
 | ||
|         pTextView->ShowCursor(TRUE, TRUE );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TextEditImp::SetFont( const Font& rNewFont )
 | ||
| {
 | ||
|     pTextEngine->SetFont(rNewFont);
 | ||
| }
 | ||
| 
 | ||
| BOOL TextEditImp::IsModified()
 | ||
| {
 | ||
|     return pTextEngine->IsModified();
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::KeyInput( const KeyEvent& rKeyEvent )
 | ||
| {
 | ||
|     BOOL bWasModified = pTextView->GetTextEngine()->IsModified();
 | ||
|     pTextView->GetTextEngine()->SetModified( FALSE );
 | ||
| 
 | ||
|     if ( !pTextView->KeyInput( rKeyEvent ) )
 | ||
|         Window::KeyInput( rKeyEvent );
 | ||
| 
 | ||
|     if ( pTextView->GetTextEngine()->IsModified() )
 | ||
|         ModifyHdl.Call( NULL );
 | ||
|     else
 | ||
|         pTextView->GetTextEngine()->SetModified( bWasModified );    // Eventuell wieder setzen
 | ||
| }
 | ||
| 
 | ||
| void TextEditImp::Paint( const Rectangle& rRect ){ pTextView->Paint( rRect );}
 | ||
| void TextEditImp::MouseButtonUp( const MouseEvent& rMouseEvent ){ pTextView->MouseButtonUp( rMouseEvent );}
 | ||
| //void TextEditImp::MouseButtonDown( const MouseEvent& rMouseEvent ){ pTextView->MouseButtonDown( rMouseEvent );}
 | ||
| //void TextEditImp::MouseMove( const MouseEvent& rMouseEvent ){ pTextView->MouseMove( rMouseEvent );}
 | ||
| //void TextEditImp::Command( const CommandEvent& rCEvt ){ pTextView->Command( rCEvt );}
 | ||
| //BOOL TextEditImp::Drop( const DropEvent& rEvt ){ return FALSE /*pTextView->Drop( rEvt )*/;}
 | ||
| //BOOL TextEditImp::QueryDrop( DropEvent& rEvt ){ return FALSE /*pTextView->QueryDrop( rEvt )*/;}
 | ||
| 
 | ||
| 
 | ||
| void TextEditImp::Command( const CommandEvent& rCEvt )
 | ||
| {
 | ||
|     switch( rCEvt.GetCommand() ) {
 | ||
|         case COMMAND_CONTEXTMENU:
 | ||
|         case COMMAND_WHEEL:
 | ||
|             GetParent()->Command( rCEvt );
 | ||
|             break;
 | ||
|         default:
 | ||
|             pTextView->Command( rCEvt );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TextEditImp::MouseButtonDown( const MouseEvent& rMouseEvent )
 | ||
| {
 | ||
|     pTextView->MouseButtonDown( rMouseEvent );
 | ||
|     HideVarContents( NULL );
 | ||
|     ShowTipTimer.Stop();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TextEditImp::MouseMove( const MouseEvent& rMEvt )
 | ||
| {
 | ||
|     pTextView->MouseMove( rMEvt );
 | ||
|     HideVarContents( NULL );
 | ||
|     if ( rMEvt.GetButtons() == 0 )
 | ||
|         ShowTipTimer.Start();
 | ||
|     if ( rMEvt.IsLeaveWindow() )
 | ||
|         ShowTipTimer.Stop();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| IMPL_LINK( TextEditImp, HideVarContents, void*, EMPTYARG )
 | ||
| {
 | ||
|     if ( nTipId )
 | ||
|     {
 | ||
|         Help::HideTip( nTipId );
 | ||
|         nTipId = 0;
 | ||
|         aTipWord = String();
 | ||
|     }
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| static const char cSuffixes[] = "%&!#@$";
 | ||
| 
 | ||
| 
 | ||
| SbxBase* TextEditImp::GetSbxAtMousePos( String &aWord )
 | ||
| {
 | ||
|     Point aPos = GetPointerPosPixel();
 | ||
|     Point aDocPos = pTextView->GetDocPos( aPos );
 | ||
|     aWord = pTextEngine->GetWord( pTextEngine->GetPaM( aDocPos ) );
 | ||
| 
 | ||
|     if ( aWord.Len() /*&& !Application::GetAppInternational().IsNumeric( aWord )*/ )
 | ||
|     {
 | ||
|         xub_StrLen nLastChar = aWord.Len()-1;
 | ||
|         String aSuffixes = CUniString( cSuffixes );
 | ||
|         if ( aSuffixes.Search( aWord.GetChar(nLastChar) ) != STRING_NOTFOUND )
 | ||
|             aWord.Erase( nLastChar, 1 );
 | ||
| 
 | ||
|         BOOL bWasError = SbxBase::IsError();    // Da eventuell im Testtool ein Fehler geschmissen wird.
 | ||
|         pAppEdit->GetBasicFrame()->Basic().DebugFindNoErrors( TRUE );
 | ||
|         SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord );
 | ||
|         pAppEdit->GetBasicFrame()->Basic().DebugFindNoErrors( FALSE );
 | ||
|         DBG_ASSERT( !( !bWasError && SbxBase::IsError()), "Error generated while retrieving Variable data for viewing" )
 | ||
|         if ( !bWasError && SbxBase::IsError() )
 | ||
|             SbxBase::ResetError();
 | ||
| 
 | ||
|         return pSBX;
 | ||
|     }
 | ||
|     return NULL;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| IMPL_LINK( TextEditImp, ShowVarContents, void*, EMPTYARG )
 | ||
| {
 | ||
|     String aWord;
 | ||
|     SbxBase* pSBX = GetSbxAtMousePos( aWord );
 | ||
|     String aHelpText;
 | ||
|     Point aPos = GetPointerPosPixel();
 | ||
| 
 | ||
|     if ( pSBX && pSBX->ISA( SbxVariable ) && !pSBX->ISA( SbxMethod ) )
 | ||
|     {
 | ||
|         SbxVariable* pVar = (SbxVariable*)pSBX;
 | ||
|         SbxDataType eType = pVar->GetType();
 | ||
|         if ( eType == SbxOBJECT )
 | ||
|         {
 | ||
|             // Kann zu Absturz, z.B. bei Selections-Objekt fuehren
 | ||
|             // Type == Object heisst nicht, dass pVar == Object!
 | ||
|             if ( pVar->GetObject() && pVar->GetObject()->ISA( SbxObject ) )
 | ||
|                 aHelpText = ((SbxObject*)(pVar->GetObject()))->GetClassName();
 | ||
|             else
 | ||
|                 aHelpText = CUniString("Object");
 | ||
|         }
 | ||
|         else if ( eType & SbxARRAY )
 | ||
|             aHelpText = CUniString("{...}");
 | ||
|         else if ( eType != SbxEMPTY )
 | ||
|         {
 | ||
|             aHelpText = pVar->GetName();
 | ||
|             if ( !aHelpText.Len() )     // Bei Uebergabeparametern wird der Name nicht kopiert
 | ||
|                 aHelpText = aWord;
 | ||
|             aHelpText += '=';
 | ||
|             aHelpText += pVar->GetString();
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     if ( aHelpText.Len() && aTipPos != aPos && aTipWord != aWord )
 | ||
|     {
 | ||
|         if ( nTipId )
 | ||
|             Help::HideTip( nTipId );
 | ||
|         nTipId = Help::ShowTip( this, Rectangle(), aHelpText );
 | ||
| 
 | ||
|         HideTipTimer.Start();
 | ||
|         aTipWord = aWord;
 | ||
|         aTipPos = aPos;
 | ||
|     }
 | ||
|     if ( nTipId && aTipPos != aPos )
 | ||
|     {
 | ||
|         Help::HideTip( nTipId );
 | ||
|         nTipId = 0;
 | ||
|         aTipWord = String();
 | ||
|     }
 | ||
| 
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TextEditImp::BuildKontextMenu( PopupMenu *&pMenu )
 | ||
| {
 | ||
|     String aWord;
 | ||
|     SbxBase* pSBX = GetSbxAtMousePos( aWord );
 | ||
|     if ( pSBX && pSBX->ISA( SbxVariable ) && !pSBX->ISA( SbxMethod ) )
 | ||
|     {
 | ||
|         SbxVariable* pVar = (SbxVariable*)pSBX;
 | ||
|         SbxDataType eType = pVar->GetType();
 | ||
| 
 | ||
|         if ( ( eType & ( SbxVECTOR | SbxARRAY | SbxBYREF )) == 0 )
 | ||
|         {
 | ||
| 
 | ||
| /*
 | ||
| Boolean
 | ||
| Currency
 | ||
| Date
 | ||
| Double
 | ||
| Integer
 | ||
| Long
 | ||
| Object
 | ||
| Single
 | ||
| String
 | ||
| Variant(Empty)
 | ||
| */
 | ||
|             switch ( eType )
 | ||
|             {
 | ||
|                 case SbxBOOL:
 | ||
| //              case SbxCURRENCY:
 | ||
| //              case SbxDATE:
 | ||
|                 case SbxDOUBLE:
 | ||
|                 case SbxINTEGER:
 | ||
|                 case SbxLONG:
 | ||
| //              case SbxOBJECT:     // kann nicht editiert werden
 | ||
|                 case SbxSINGLE:
 | ||
|                 case SbxSTRING:
 | ||
| 
 | ||
|                 case SbxVARIANT:    // Taucht wohl auch nicht auf. stattdessen SbxEMPTY
 | ||
|                 case SbxEMPTY:
 | ||
|                     {
 | ||
|                         pAppEdit->GetBasicFrame()->SetEditVar( pVar );
 | ||
|                         if ( !pMenu )
 | ||
|                             pMenu = new PopupMenu();
 | ||
|                         else
 | ||
|                             pMenu->InsertSeparator();
 | ||
| 
 | ||
|                         pMenu->InsertItem( RID_POPUPEDITVAR, ((BasicFrame*)GetpApp()->GetAppWindow())->GenRealString( GEN_RES_STR1( IDS_EDIT_VAR, aWord ) ) );
 | ||
|                     }
 | ||
|                     break;
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| DBG_NAME(TextEdit)
 | ||
| 
 | ||
| TextEdit::TextEdit( AppEdit* pParent, const WinBits& aBits )
 | ||
| : aEdit( pParent, aBits | WB_NOHIDESELECTION )
 | ||
| , pBreakpointWindow( NULL )
 | ||
| , bFileWasUTF8( FALSE )
 | ||
| , bSaveAsUTF8( FALSE )
 | ||
| {
 | ||
| DBG_CTOR(TextEdit,0);
 | ||
| }
 | ||
| 
 | ||
| TextEdit::~TextEdit()
 | ||
| {DBG_DTOR(TextEdit,0);}
 | ||
| 
 | ||
| void TextEdit::Highlight( ULONG nLine, xub_StrLen nCol1, xub_StrLen nCol2 )
 | ||
| {
 | ||
|     if ( nLine )    // Kann eigentlich nicht vorkommen, au<61>er bei Fehler 'Sub erwartet' in erster Zeile
 | ||
|         nLine--;
 | ||
| 
 | ||
|     String s = aEdit.pTextEngine->GetText( nLine );
 | ||
| 
 | ||
|     if( nCol1 == STRING_NOTFOUND )
 | ||
|         // Keine Spalte angegeben
 | ||
|         nCol1 = 0, nCol2 = STRING_NOTFOUND;
 | ||
|     if( nCol2 == STRING_NOTFOUND )
 | ||
|     {
 | ||
|         nCol2 = s.Len();
 | ||
|     }
 | ||
|     // Anpassung an den Precompiler | EditText != Compilierter Text
 | ||
|     if ( nCol2 > s.Len() )
 | ||
|         nCol2 = s.Len();
 | ||
|     if ( nCol1 >= nCol2 )
 | ||
|         nCol1 = 0;
 | ||
| 
 | ||
|     // Da nCol2 u.U. hinter das aktuelle Statement zeigt
 | ||
|     // (weil dort schon das naechste beginnt), muessen
 | ||
|     // wird am Ende evtl. Whitespace, einen Doppelpunkt
 | ||
|     // und mehr Whitespace entfernen
 | ||
|     BOOL bColon = FALSE;
 | ||
| 
 | ||
|     while ( s.GetChar( nCol2 ) == ' ' && nCol2 > nCol1 && !bColon )
 | ||
|     {
 | ||
|         nCol2--;
 | ||
|         if ( s.GetChar( nCol2 ) == ':' )
 | ||
|         {
 | ||
|             nCol2--;
 | ||
|             bColon = TRUE;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     aEdit.ViewMoved();
 | ||
|     aEdit.pTextView->SetSelection( TextSelection(TextPaM(nLine,nCol2+1), TextPaM(nLine,nCol1)) );
 | ||
|     if ( aEdit.ViewMoved() )
 | ||
|     {
 | ||
|         aEdit.pTextView->SetSelection( TextSelection(TextPaM(TEXT_PARA_ALL,1)) );   // fix #105169#
 | ||
|         aEdit.pTextView->SetSelection( TextSelection(TextPaM((nLine>=2?nLine-2:0),nCol2+1)) );
 | ||
|         aEdit.pTextView->SetSelection( TextSelection(TextPaM(nLine,nCol2+1), TextPaM(nLine,nCol1)) );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TextEdit::Delete(){ aEdit.pTextView->KeyInput( KeyEvent( 0, KeyCode( KEYFUNC_DELETE ) )); }
 | ||
| void TextEdit::Cut(){ aEdit.pTextView->Cut(); }
 | ||
| void TextEdit::Copy(){ aEdit.pTextView->Copy(); }
 | ||
| void TextEdit::Paste(){ aEdit.pTextView->Paste(); }
 | ||
| void TextEdit::Undo(){ aEdit.pTextView->Undo(); }
 | ||
| void TextEdit::Redo(){ aEdit.pTextView->Redo(); }
 | ||
| String TextEdit::GetSelected(){ return aEdit.pTextView->GetSelected(); }
 | ||
| TextSelection TextEdit::GetSelection() const{ return aEdit.pTextView->GetSelection(); }
 | ||
| void TextEdit::SetSelection( const TextSelection& rSelection ){ aEdit.pTextView->SetSelection( rSelection ); }
 | ||
| 
 | ||
| USHORT TextEdit::GetLineNr() const
 | ||
| {
 | ||
|     return aEdit.pTextView->GetSelection().GetEnd().GetPara()+1;
 | ||
| }
 | ||
| 
 | ||
| void TextEdit::ReplaceSelected( const String& rStr ){ aEdit.pTextView->InsertText(rStr); }
 | ||
| BOOL TextEdit::IsModified(){ return aEdit.IsModified(); }
 | ||
| 
 | ||
| String TextEdit::GetText() const
 | ||
| {
 | ||
|     return aEdit.pTextEngine->GetText( GetSystemLineEnd() );
 | ||
| }
 | ||
| 
 | ||
| void TextEdit::SetText( const String& rStr ){ aEdit.pTextEngine->SetText(rStr); aEdit.pTextEngine->SetModified( FALSE ); }
 | ||
| void TextEdit::SetModifyHdl( Link l ){ aEdit.SetModifyHdl(l); }
 | ||
| BOOL TextEdit::HasText() const { return aEdit.pTextEngine->GetTextLen() > 0; }
 | ||
| 
 | ||
| // Es wird entweder ab Beginn oder ab Markierungsbegin + 1 gesucht.
 | ||
| 
 | ||
| BOOL TextEdit::Find( const String& s )
 | ||
| {
 | ||
|     DBG_CHKTHIS(TextEdit,0);
 | ||
| 
 | ||
|     TextSelection aSelection = aEdit.pTextView->GetSelection();
 | ||
|     USHORT nPara = aSelection.GetStart().GetPara();
 | ||
|     xub_StrLen nIndex = aSelection.GetStart().GetIndex();
 | ||
| 
 | ||
|     if ( aSelection.HasRange() )
 | ||
|         nIndex ++;
 | ||
| 
 | ||
|     while ( nPara <= aEdit.pTextEngine->GetParagraphCount() )
 | ||
|     {
 | ||
|         String aText = aEdit.pTextEngine->GetText( nPara );
 | ||
| 
 | ||
|         nIndex = aText.Search( s, nIndex );
 | ||
|         if( nIndex != STRING_NOTFOUND )
 | ||
|         {
 | ||
|             aEdit.pTextView->SetSelection( TextSelection( TextPaM( nPara, nIndex ), TextPaM( nPara, nIndex + s.Len() ) ) );
 | ||
|             return TRUE;
 | ||
|         }
 | ||
|         nIndex = 0;
 | ||
|         nPara++;
 | ||
|     }
 | ||
|     return FALSE;
 | ||
| }
 | ||
| 
 | ||
| BOOL TextEdit::Load( const String& aName )
 | ||
| {
 | ||
| DBG_CHKTHIS(TextEdit,0);
 | ||
|     BOOL bOk = TRUE;
 | ||
|     SvFileStream aStrm( aName, STREAM_STD_READ );
 | ||
|     if( aStrm.IsOpen() )
 | ||
|     {
 | ||
|         String aText, aLine;
 | ||
|         BOOL bIsFirstLine = TRUE;
 | ||
|         rtl_TextEncoding aFileEncoding = RTL_TEXTENCODING_IBM_850;
 | ||
|         while( !aStrm.IsEof() && bOk )
 | ||
|         {
 | ||
|             aStrm.ReadByteStringLine( aLine, aFileEncoding );
 | ||
|             if ( bIsFirstLine && IsTTSignatureForUnicodeTextfile( aLine ) )
 | ||
|             {
 | ||
|                 aFileEncoding = RTL_TEXTENCODING_UTF8;
 | ||
|                 bFileWasUTF8 = TRUE;
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 if ( !bIsFirstLine )
 | ||
|                     aText += '\n';
 | ||
|                 aText += aLine;
 | ||
|                 bIsFirstLine = FALSE;
 | ||
|             }
 | ||
|             if( aStrm.GetError() != SVSTREAM_OK )
 | ||
|                 bOk = FALSE;
 | ||
|         }
 | ||
|         aText.ConvertLineEnd();
 | ||
|         SetText( aText );
 | ||
|     }
 | ||
|     else
 | ||
|         bOk = FALSE;
 | ||
|     return bOk;
 | ||
| }
 | ||
| 
 | ||
| BOOL TextEdit::Save( const String& aName )
 | ||
| {
 | ||
| DBG_CHKTHIS(TextEdit,0);
 | ||
|     BOOL bOk = TRUE;
 | ||
|     SvFileStream aStrm( aName, STREAM_STD_WRITE | STREAM_TRUNC );
 | ||
|     rtl_TextEncoding aFileEncoding = RTL_TEXTENCODING_IBM_850;
 | ||
|     if( aStrm.IsOpen() )
 | ||
|     {
 | ||
|         if ( bFileWasUTF8 || bSaveAsUTF8 )
 | ||
|         {
 | ||
|             aStrm << TT_SIGNATURE_FOR_UNICODE_TEXTFILES;
 | ||
|             aStrm << sal_Char(_CR);
 | ||
|             aStrm << sal_Char(_LF);
 | ||
|             aFileEncoding = RTL_TEXTENCODING_UTF8;
 | ||
|         }
 | ||
|         String aSave = GetText();
 | ||
|         aSave.ConvertLineEnd(LINEEND_CRLF);
 | ||
|         aStrm << ByteString( aSave, aFileEncoding ).GetBuffer();
 | ||
|         if( aStrm.GetError() != SVSTREAM_OK )
 | ||
|             bOk = FALSE;
 | ||
|         else
 | ||
|             aEdit.pTextEngine->SetModified(FALSE);
 | ||
|     } else bOk = FALSE;
 | ||
|     return bOk;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void TextEdit::BuildKontextMenu( PopupMenu *&pMenu )
 | ||
| {
 | ||
|     DataEdit::BuildKontextMenu( pMenu );
 | ||
|     aEdit.BuildKontextMenu( pMenu );
 | ||
| }
 | ||
| 
 | ||
| 
 |